All docs ▾

Docs / Using Vex / Memory

Memory

Lessons, the local judge, decay, and why memory never touches execution.

Vex keeps two kinds of memory. Session memory is the per-session narrative the runtime writes when a conversation is compacted, which the agent recalls on demand. Long-term memory is a curated store of lessons, the durable rules and observations the agent proposes, which survive across sessions and get retrieved when they look relevant again.

Nothing the agent proposes is remembered just because it proposed it. A lesson has to pass a deterministic filter and then a local judge before it becomes a knowledge entry. And no matter how confident a memory is, it is advisory only: it can inform what the agent says and suggests, and it can never move funds.

The lessons pipeline

A lesson starts as a proposal from the agent itself and walks a fixed path before it is allowed to persist.

  1. The agent proposes

    Mid-session, the agent calls MemorySuggest with a candidate lesson, a claim it thinks is worth carrying forward. Proposing costs it nothing and grants it nothing. Persisted memory text is English by contract, so a non-English suggestion is rejected outright.

  2. Deterministic filters, fail-closed

    Before any model sees the candidate, plain code checks it: live state, exact duplicates, near-duplicates, the mundane, the low-confidence, and expiry terminals, plus a recurrence gate. Only survivors escalate. The filters are fail-closed: when a check cannot be completed, the lesson is rejected rather than waved through.

  3. A judge scores it on five axes

    Survivors go to an LLM judge running against your own provider account, scoring the candidate on grounding, durability, novelty, generalizability and process-not-outcome, then returning one verdict. A broken or invalid verdict promotes nothing.

  4. The verdict is applied

    Promote, supersede, retain, reject or expire. See the table below. Promotion writes a knowledge entry into the local Postgres and embeds it with pgvector so it can be retrieved later, and a supersede retires its predecessor in the same transaction.

VerdictWhat happens
promoteThe lesson becomes a new knowledge entry and is embedded.
supersedeThe lesson replaces an existing entry it contradicts or sharpens; the old one is retired in the same transaction.
retainAn existing entry is confirmed and kept as-is; nothing new is written.
rejectThe candidate is discarded.
expireAn entry that no longer holds is retired.

The knowledge graph is bi-temporal: superseding a lesson retracts its edges by invalidating them rather than deleting them, so the audit history is preserved and only what is eligible to come back changes.

Retrieval and decay

Retrieval is dual-trace: one ranked list is blended from two sources, the promoted knowledge entries and the fresh candidates that have not been consolidated yet. Both are reached by meaning, through the pgvector embedding (768-dimensional, produced by the local embeddings runtime), and a confirmed entry always outranks an unconsolidated candidate at equal similarity. A candidate is a soft signal, never a hard constraint.

On top of that, a search does one bounded hop over the knowledge graph from its strongest results, so a lesson attached to the same token, venue or chain can surface even when you would have phrased it differently. Graph results are scored below every seed and only fill slots the direct results left free.

Old lessons fade rather than pile up. An entry’s activation carries a time decay with an exponential half-life in days since it was last reinforced, floored above zero: decay is erosion of influence, never deletion. The half-life is regime-aware, so a lesson that matches the current market regime decays slower and one that contradicts it decays faster, within hard bounds.

The regime itself comes from a daily market-regime classifier, a background worker that gathers web and X evidence and has a model classify the day. It runs only when you have configured the search or X credentials it needs, and it is advisory-only by design: it modulates decay and recall rank, never sizing, approval or execution.

The agent reaches memory through MemorySearch, MemoryGet and MemoryHistory, and session memory through SessionMemorySearch. The app has a memory panel where you can read session memory, long-term entries and their privacy state yourself.

Memory is advisory only.

Memory never controls execution, sizing, approvals or signing. A knowledge entry cannot authorise a swap, cannot raise a permission level, cannot pre-approve an intent and cannot cause a transaction to be signed. It is context handed to the model, and the model still has to go through the same approval path as always. See Approvals & the Safety Contract.

This matters because memory is written from tool output and conversation, both of which can be attacker-influenced. Vex’s standing doctrine is that tool output is data, not instruction; keeping memory out of the execution path means a poisoned lesson is at worst bad advice you can see, not a signature you did not intend.

Secrets and privacy

Secrets are redacted at the door: candidate lessons are scrubbed before they are stored, with the same redaction applied again at promotion as defence in depth. Memory, embeddings and conversations all live in the local Postgres that the app runs for you, and every published port in that stack binds to 127.0.0.1 rather than the LAN. The untrusted renderer never imports this subsystem at all. See Privacy.

Switching embedding models

Knowledge entries are embedded with whatever embedding model you configured, so changing that model invalidates the vectors. Vex ships a portability workflow for exactly this: export the knowledge, reconfigure the model, then import or re-embed.

make knowledge-export
# reconfigure EMBEDDING_MODEL / EMBEDDING_DIM
make knowledge-import
# or, to rebuild vectors in place at the SAME dimension:
make knowledge-reembed

Re-embedding is same-dimension only: if the configured EMBEDDING_DIMdiffers from the dimension already in the database, it refuses and points you at export, wipe and import instead. The embedding model and dimension are set in the wizard’s embedding step and live as environment variables afterwards. See Environment variables and First run.