Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
340 changes: 145 additions & 195 deletions CLAUDE.md

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion skill.lock
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,5 @@
# CI diffs plugin/skills/memvara against that SHA. skill-sync.yml updates this
# file when it opens a PR.
repo=memvara/memvara
sha=6527a4b081ec8c7c76b4f7a701874c4209470f97
sha=d4e6b2f0994a5e97f3504c9032a8969b2e36d0a5
path=memvara/skills/memvara
42 changes: 39 additions & 3 deletions skills/memvara/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,10 @@ Read before you assert. Anything you say about what is remembered — "you told
me X", "I have nothing on file" — must come from a tool result **in the current
turn**. If you have not looked, say so, then look.

To open a session, one `memory_profile` call does the work of calling
`memory_standing` and then `memory_since`. When the server does not list it,
make those two calls instead.

When they say a memory is wrong, do this order: `memory_recall`,
`memory_search` (you need the claim id), `memory_why` (put the excerpt in front
of them). The excerpt is the **evidence for** which write comes next, not their
Expand Down Expand Up @@ -121,6 +125,17 @@ long, and a stored sentence saying a defect is fixed is not the fix.
Then say what you closed, in the same message as the work. A correction nobody
is told about is one they cannot argue with.

Leave the reason on the record too. Every closing write takes one, including a
`memory_remember` that names the value it `replaces`, and the next session sees
it beside the closed note. Write the evidence in one sentence ("the deploy log
shows the gate installed at 14:02"), not the conversation that produced it.

When a whole topic is over, or was wrong from the start, one query can close all
of it, and the first call only shows you the list. Read every line before you
confirm, because the match is loose. If one line should stay, do not confirm;
close the others by id instead. When a note you store adds detail to one already
there, link the two so the next `memory_why` shows how they fit.

Call `memory_stats` once before you write. If the session field is not `*`, the
server was launched with `MEMVARA_SESSION` set and the note will not carry over
— say so. If stats say `fast-path-only`, write triples with `memory_remember`: a
Expand Down Expand Up @@ -161,6 +176,27 @@ user the steps and let them see where you got it; a conclusion with the middle
removed is something they have to take on trust, and the middle is the part
they can correct.

**A document or a fact.** When they hand you something they want kept whole — a
spec, a runbook, a README, notes from a meeting — store it as a document, so later
questions get its own sentences back. When they tell you one thing about
themselves or their work, write the fact. A document is not a way to avoid
deciding: if a line inside it is something you will need as a fact next week,
write that fact as well. Give the document a stable name of your own, such as its
path, so a newer version sent later replaces the old one instead of sitting
beside it.

Deleting a document is different from every other removal here. Its text is
erased and cannot be brought back. The notes that came only from it are retired,
not erased, so the record of what was believed stays. Before you delete, say which
of those two they are getting, and when they only want a newer version, send the
document again rather than deleting it.

A summary at the top of a recall block is there because you asked for one. It
is a model's reading of the notes under it, not a note. When the two differ,
answer from the notes. Never store the summary with `memory_remember`: that
files a paraphrase as though somebody had said it, and the next session cannot
tell the difference.

## Other jobs

| They asked | Open |
Expand All @@ -177,6 +213,6 @@ lookup and nothing about the two people. Report it as such. "I have no record
tying them together" is true; "they have no connection" is a claim about the
world that no memory tool can support.

`memory_forget` is not erasure. Real deletion is an operator action on the
console or REST, and is deliberately not a tool. Never say you deleted data if
you only retired a claim.
`memory_forget` is not erasure. Erasing a memory is an operator action on the
console or REST, and is deliberately not a tool; the only text a tool erases is
a stored document's own. Never say you deleted data if you only retired a claim.
16 changes: 11 additions & 5 deletions skills/memvara/references/hosted-mcp.md
Original file line number Diff line number Diff line change
Expand Up @@ -77,12 +77,14 @@ imports `memvara`, not whichever `python3` a GUI `PATH` finds.
`npx memvara` bridges a stdio client to the hosted server and signs you in on
first run, for a machine with no Python at all.

## The fourteen tools
## The twenty-two tools

`memory_recall`, `memory_search`, `memory_neighborhood`, `memory_paths`,
`memory_ask`, `memory_since`, `memory_standing`, `memory_add`,
`memory_remember`, `memory_forget`, `memory_end`, `memory_history`,
`memory_why`, `memory_stats`.
`memory_ask`, `memory_since`, `memory_standing`, `memory_profile`,
`memory_add`, `memory_remember`, `memory_forget`, `memory_end`,
`memory_end_matching`, `memory_forget_matching`, `memory_link`,
`memory_history`, `memory_why`, `memory_stats`, `memory_add_document`,
`memory_get_document`, `memory_list_documents`, `memory_delete_document`.

That is what this library serves. **A hosted deployment can be behind it**, and
saying so is more useful than a number that is wrong for one of the two: a
Expand All @@ -92,4 +94,8 @@ simply whether the tool you want is one you can see. A tool that is absent is a
deployment that has not caught up, not a tool that was removed.

`erase`, `purge`, `reset`, `consolidate` are not tools. A read-only server
hides the four write tools.
hides the nine write tools, and a server started with a feature switched
off hides that feature's tools: `MEMVARA_FEATURE_PROFILE=0` hides
`memory_profile`, `MEMVARA_FEATURE_FORGET_MATCHING=0` hides the two
`_matching` tools, `MEMVARA_FEATURE_LINKS=0` hides `memory_link`, and
`MEMVARA_FEATURE_DOCUMENTS=0` hides the four document tools.
13 changes: 10 additions & 3 deletions skills/memvara/references/scopes.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# Scope

A store is partitioned as `tenant / user / agent / session`. `*` means that
field is unbound.
A store is partitioned as `tenant / user / project / agent / session`. `*`
means that field is unbound.

On MCP the scope is fixed when the server starts. No tool argument changes
it. Call `memory_stats` once, early, in any conversation where you expect to
Expand All @@ -28,12 +28,19 @@ your machine.
For a custom Python loop, `mem.scope(user=...)` per request. One `Memvara`
per process.

## What the four fields mean
## What the five fields mean

- **tenant** — the isolation boundary above a user. Default `default`.
- **user** — who the facts are about. Unset on a local server means the
whole tenant, which is right for a single-person machine and wrong for a
product with customers.
- **project** — the repository the facts were learned in, as
`host/owner/repo`. A local server works it out from the git remote of the
directory it started in, so every clone and worktree of one repository
shares it. A preference whose predicate is declared global is written
without a project, so it follows the user into every repository; a fact
about one codebase stays with that codebase. `MEMVARA_PROJECT` names it
explicitly, and `MEMVARA_FEATURE_PROJECT_SCOPE=0` stops it being worked out.
- **agent** — which program wrote it. Usually unbound.
- **session** — this conversation. Leave unbound for anything that should
still be true tomorrow.
14 changes: 11 additions & 3 deletions skills/memvara/references/time.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,21 @@ On the **library and REST**:
alongside either axis raises rather than picking one.

On **MCP**: `memory_search` takes `as_of` and `valid_at`, not `known_at`.
Passing both of the two it has is refused.
Passing both of the two it has is refused. `memory_recall` takes `valid_at`
only, and its header then names the day; it refuses `as_of`, because its
output is a prompt and rewinding belief would put a since-retired record in it.

Reach for `valid_at`. Asking about someone's earlier city, job or year is
asking about the world, and `as_of` answers something else: it rewinds
belief as well, so every later correction disappears — including one that
was made about exactly the period being asked about. `as_of` earns its
place only when they want what you *used to think*.

A server that has a model set up also reads dates out of the question itself,
so "where did I live in 2019" can come back dated without you passing
anything. That reading is a model's guess. When the person names a day, pass
`valid_at` yourself: yours always wins, and it needs no model at all.

A fact backfilled so that both its ends are already past is reachable
through `valid_at` alone. Its write receipt says so at the time, and the
tool description says why.
Expand Down Expand Up @@ -52,8 +59,9 @@ values and the gap between them. Answering it with `valid_at` alone hides the
very thing being asked about, because `valid_at` is written from today and a
later correction is already folded in.

So: `memory_recall` for what is the case, `memory_search` with `valid_at` for
one past reading, `memory_history` for the versions of a single fact with ids
So: `memory_recall` for what is the case, `memory_recall` with `valid_at` for
what was the case on a day, `memory_search` with `valid_at` for one past
reading with ids, `memory_history` for the versions of a single fact with ids
to act on, and this when someone is holding an old answer and wants to know why
it no longer matches.

Expand Down
17 changes: 17 additions & 0 deletions skills/memvara/references/write-and-correct.md
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,23 @@ undeclared predicate decays at the slow default — a two-year half-life — so
a fact that changed this morning still ranks as fresh long after it stopped
being true, and nothing ever reports it.

## "may replace: [id] ..."

This line appears only on a server whose operator turned
`MEMVARA_ADVISE_REPLACEMENTS` on. It means the store could not compare your
new fact with the named one itself, because the two are filed under
different names, and the model thinks yours is the newer version. The
model is wrong about one time in ten, so read the named fact before acting,
then pick the closure the line offers:

- The world moved and yours is the current value: `memory_end` the named id.
- The old record was never right: `memory_forget` it.
- Both hold, or they are about different things: do nothing.

If the same two spellings keep producing this line, the fix is on the
server: `merge_predicate` folds one predicate name onto the other and moves
the claims already filed under it. Tell them; it is not a tool.

## Carry the turn ids forward

Half the dispute sequence above runs on the excerpt: step 3 puts it in front
Expand Down
Loading