Skip to content

Tutorial 4: Long-term memory with Milvus

malac’s memory works out of the box as Markdown files. In this tutorial you add a local Milvus so malac can search memories by meaning and recall relevant ones automatically, then watch a fact saved in one session shape the next.

You need Docker, malac from tutorial 1, and an embedding model: either Ollama locally or an OpenAI key.

  1. Start Milvus standalone. In a directory where Milvus may keep its data:

    mkdir -p ~/milvus && cd ~/milvus
    curl -sfL https://raw.githubusercontent.com/milvus-io/milvus/master/scripts/standalone_embed.sh -o standalone_embed.sh
    bash standalone_embed.sh start

    The script pulls the Milvus image and starts a container listening on port 19530. The first start takes a minute.

  2. Check the REST API. malac uses Milvus’s REST API v2:

    curl -s -X POST http://localhost:19530/v2/vectordb/collections/list -d '{}'
    {"code":0,"data":[]}
  1. Pick an embedding model. With Ollama:

    ollama pull nomic-embed-text
  2. Add the memory settings to ~/.malac/config.toml:

    [providers.local]
    kind = "openai"
    base_url = "http://localhost:11434/v1"
    [memory.vector]
    url = "http://localhost:19530"
    collection = "malac_memory"
    [memory.embeddings]
    provider = "local"
    model = "nomic-embed-text"

    With OpenAI instead, leave out [providers.local] and use provider = "openai" and model = "text-embedding-3-small".

    If malac’s daemon is already running, restart it so every tab loads the new settings: malac daemon restart.

  3. Index what you already have. If you saved memories before, put them in the collection. malac creates it on first use:

    malac memory reindex
    indexed 0 memories

    Zero is fine on a fresh install.

  1. Make a project and start a session.

    mkdir -p ~/memo-demo && cd ~/memo-demo && git init -q
    malac
  2. Tell malac a few things worth remembering.

    Remember for this project: we use pytest, never unittest, and tests live
    in tests/. And remember for me everywhere: I prefer short commit messages
    in the imperative mood.

    The memory tools never ask for permission:

    ● memory_save test-conventions
    ⎿ Saved memory `test-conventions` to /Users/you/memo-demo/.malac/memory/test-conventions.md
    ● memory_save commit-style
    ⎿ Saved memory `commit-style` to /Users/you/.malac/memory/commit-style.md

    The first is a project memory, stored in the repository’s .malac/memory/. The second is global, in ~/.malac/memory/. Each save also embedded the memory into Milvus.

  3. Look at the files. Exit the session (/exit) and read one:

    cat .malac/memory/test-conventions.md
    ---
    name: test-conventions
    description: Tests use pytest (never unittest) and live in tests/
    updated: 2026-10-25T14:10:03.512+00:00
    ---
    This project uses pytest, never unittest. Tests live in tests/.
    malac memory
    [Global] commit-style: Prefers short commit messages in the imperative mood /Users/you/.malac/memory/commit-style.md
    [Project] test-conventions: Tests use pytest (never unittest) and live in tests/ /Users/you/memo-demo/.malac/memory/test-conventions.md

    The files are the source of truth. You can edit them by hand; run malac memory reindex afterwards so the vectors follow.

  1. Search by meaning. The query shares no keywords with the memory:

    malac memory search how should I check that my code works
    0.62 test-conventions: Tests use pytest (never unittest) and live in tests/

    The number is the cosine similarity. Without Milvus, the same search falls back to keywords and would find nothing here.

  2. Let auto recall do it. Start a fresh session and ask for something related, without mentioning the conventions:

    cat > slug.py <<'EOF'
    def slugify(text):
    return "-".join(text.lower().split())
    EOF
    malac -y -p add tests for slugify

    malac creates tests/test_slug.py with pytest-style test functions and runs pytest (install it with python3 -m pip install pytest if you want the run to pass), because the prompt was embedded and the matching memory was attached to it before the model saw it.

  3. See what was attached. The recalled memories are part of the prompt in the transcript:

    malac sessions # the newest session is first; copy its id
    malac sessions show <id>
    main 019a2c11-… · lora/default · 2026-10-25 14:14
    › <recalled-memories>
    ...

    Up to memory.recall_limit memories (default 5) with a similarity of at least 0.4 are attached to each prompt of 8 characters or more.

malac memory # list what is saved
rm .malac/memory/test-conventions.md # forget by deleting the file…
malac memory reindex # …and re-sync the collection

Or ask malac to forget something (“forget the commit style memory”); memory_forget deletes the file and its vector. Stop Milvus with bash ~/milvus/standalone_embed.sh stop.

Replace [memory.vector] with your cluster’s public endpoint and an API key:

[memory.vector]
url = "https://<cluster-id>.<region>.zillizcloud.com"
token_env = "ZILLIZ_API_KEY"
database = "default"
collection = "malac_memory"

Everything else in this tutorial stays the same. See Vector memory with Milvus.

Next: Running malac unattended.

malac is created by lobirus and released under the MIT license. About malac