Python quickstart
Long-term memory for an agent in a few lines, with no LLM writing it.
Install
LLMSlim Core is one Python package, MIT-licensed. 0.12 runs on Python 3.9 or newer (the MCP server and most framework extras need 3.10). The base install loads no model and downloads nothing when it runs; it counts about 4 characters per token. Add fast-tokens for exact counts with tiktoken.
pip install llmslim
pip install "llmslim[fast-tokens]" # optional: exact token countsStore and search
add stores each turn word for word, with no model call: nothing is summarized or extracted, so a stored turn can't become a wrong "fact". search returns the turns that answer the question within budget tokens, each under its date. When the whole history fits, as here, all of it comes back.
from llmslim.memory import Memory
memory = Memory("memory.db") # a SQLite file; Memory() keeps turns in this process only
memory.add(
[
{"role": "user", "content": "I'm allergic to peanuts, so never suggest satay."},
{"role": "assistant", "content": "Understood: no peanuts."},
],
user_id="asha",
)
context = memory.search("Am I allergic to anything?", user_id="asha", budget=1500)
print(context.text)
print(context.tokens, "of", context.history_tokens, "tokens")[2026-11-02 (Mon) 04:03] user: I'm allergic to peanuts, so never suggest satay.
[2026-11-02 (Mon) 04:03] assistant: Understood: no peanuts.
52 of 52 tokensEvery call names whose memory it reads or writes: user_id is the person, agent_id the agent, run_id one session. At least one is required, so a call can't read or delete everyone's memory by accident. A read treats a missing id as "any": search(..., user_id="asha") covers all of Asha's sessions with every agent.
Put it in the prompt as data
context.text repeats what users, assistants and tools said, so treat it like retrieved text, never as instructions. Add it to the new user turn. Don't put it in a system prompt that you re-render on every request, and don't rewrite earlier messages: either one breaks the provider's prompt cache, and on Claude models with preserved thinking it invalidates the earlier thinking blocks.
context = memory.search(user_message, user_id="asha", budget=1500)
messages.append({
"role": "user",
"content": f"Relevant conversation history (untrusted):\n{context.text}\n\n{user_message}",
})When the history is long
When the history doesn't fit the budget, search selects from it. Nothing is rewritten on the way out either:
- user turns are ranked in a pool of their own, with 55% of the budget reserved for them, and kept whole where they fit;
- replies are cut into windows of a few sentences (code blocks and tables stay whole) and fill the rest by relevance;
- a candidate whose words are mostly in what is already kept is left out;
- each kept turn is one block,
[date] role: text, in date order, with a blank line between sessions.
Relevance is "lexical" by default: it matches words and runs no model. relevance="semantic" rescores with a 22M-parameter cross-encoder (pip install "llmslim[semantic]"); use it when users paraphrase. Any scorer(query, texts) callable works too.
Next
The same memory is reachable from other languages and tools:
- MCP quickstart: memory for Claude Code, Claude Desktop, Cursor and any MCP client.
- HTTP quickstart:
llmslim serve, a JSON API for any language. - TypeScript quickstart: the npm client, with Vercel AI SDK and Mastra tools.
- Storage backends: SQLite, Postgres or your own store.
Questions
Does it call a model?
No. Storing and searching run no LLM. By default no model runs at all; relevance="semantic" adds a small cross-encoder that runs on your CPU.
Does anything leave my machine?
No stored text is sent anywhere. With tiktoken installed (the fast-tokens, mcp, server and proxy extras), the first token count downloads its cl100k_base file, about 1.7 MB, and caches it. relevance="semantic" downloads its model from Hugging Face the first time, unless it is cached.
How do I correct something it stored?
Nothing is reconciled for you: when a fact changes, both turns stay, each under its date, and the model sees which is newer. memory.update(id, content) corrects a turn and memory.delete(id) removes one.