RE-call Setup

The install path

Seven steps from nothing to a memory that answers you.


Do them in order. Each one gives you something you can check before moving on, so you never get three steps deep before finding out something went wrong.

00

Before you start

You need two things installed, and a terminal open. On Windows that is PowerShell, on macOS and Linux it is Terminal. Everything below is typed there.

WhatWhy RE-call needs itWhere
Python 3.11 or newer RE-call is a Python package. 3.11 is the floor, and 3.12 to 3.14 are supported. python.org
Docker Desktop Your memory is stored in PostgreSQL with the pgvector extension. Docker gives you both, correctly configured, in one command. docker.com

On Windows, install Python from python.org

Not from the Microsoft Store. The Store build sandboxes file paths in ways that break indexing a folder on disk.

Check both are ready. Two commands, two version numbers back.

python --versiondocker --version

You should see

Output
Python 3.12.7
Docker version 27.3.1, build ce12230

One convention for the whole page

Windows uses python, macOS and Linux use python3. Pick your tab once at the top of any command block and every other block on the site switches with it.

Version number missing or too old? Fixing Python and Docker.

01

Start the database

RE-call keeps your memory in PostgreSQL and searches it with pgvector. This one command downloads a PostgreSQL 18 image that already has pgvector built in, and starts it on your machine.

docker run -d --name recall-db -e POSTGRES_USER=recall -e POSTGRES_PASSWORD=recall -e POSTGRES_DB=recall -p 5432:5432 pgvector/pgvector:pg18

The first run downloads the image, which takes a minute or two. After that it starts instantly.

Check it is running

Any shell
docker ps
Output
CONTAINER ID   IMAGE                    STATUS         PORTS                    NAMES
a1b2c3d4e5f6   pgvector/pgvector:pg18   Up 4 seconds   0.0.0.0:5432->5432/tcp   recall-db
Why a container instead of installing PostgreSQL properly

Because pgvector is an extension, and installing it against a native PostgreSQL means matching compiler toolchains to server versions. The container ships the pair already working. If you already run PostgreSQL and know how you want to add the vector extension, use your own instance and substitute its connection string everywhere this guide writes postgresql://recall:recall@localhost:5432/recall.

Your data lives inside the container. To keep it across a container rebuild, add -v recall_pgdata:/var/lib/postgresql to the command above.

Port already in use, or Docker not running? Database problems.

02

Install RE-call

One package from PyPI. The fastembed part pulls in a small embedding model that runs on your own machine, so building and searching memory never sends your text anywhere.

python -m pip install "recall-rag[fastembed]"

The package is recall-rag, not recall

The name recall on PyPI belongs to an unrelated project. Installing both into the same environment breaks the import. You install recall-rag, and in code and commands it is spelled recall.

Check it installed

python -m recall.cli --help

A usage message listing commands such as setup, schema, index and search means you are ready.

What the square brackets mean, and the other options

The brackets are optional extras. Plain recall-rag installs with no embedding model at all, which leaves you with a placeholder that is only useful for testing plumbing. [fastembed] adds the local model this guide uses, roughly 130 MB, downloaded the first time you index something.

Others exist for later: [mcp] for the Claude Code server in step 7, [rerank] for a quality upgrade on results, [voyage] for a cloud embedder. You can add them at any time by re-running the install with a longer bracket list.

Command not found, or a permissions error? Install problems.

03

Run the setup wizard

This asks you a short series of questions, then writes your answers to a .env file in the current folder so you never have to repeat them. Run it from whichever folder you want your memory to live in.

It sets the database up for you

Once you pick an embedder the wizard creates the tables at the matching vector width, printing Prepared 'chunks' for 384 dimensions. as it goes. There is no separate schema command to run first. If it cannot reach the database it says so and tells you the command to run by hand.

python -m recall.cli setup

It opens by measuring your machine, then asks its questions. Here is every one of them, with the answer to give on a first install.

It asksAnswerBecause
Is data security necessary for this installation? Y Keeps every cloud option hidden, so nothing you index can leave the machine.
Choose the embedder 2, fastembed The local model you installed in step 2. The wizard prepares the database at its 384 wide vector size for you.
Choose whether to enable reranking 1, none Reranking improves result quality but downloads another model and slows each search. Add it once the basics work.
Choose the sparse retrieval backend 1, postgres fts Uses the database you already have. The alternative needs an NVIDIA GPU.
Enable the entailment judge? N An extra check on whether a result really supports an answer. Useful later, another model download now. You may not be asked this at all.
Enable the optional reasoning arm? N Records provider settings for a reasoning arm that the shipped tools do not call yet. The default reasoning tools stay deterministic either way. Because you answered yes to security, only a local server such as Ollama is offered, and it also needs the extract extra. Say no now and add it later once you have one running. This question exists from version 0.9.5 onward: on 0.9.4 you will not see it.
Scaffold CLAUDE.md and a memory/ directory? Y Creates the folder your memory files go in, and the instructions Claude reads. Step 6 uses both.
Calibrate the threshold now? N Calibration measures how confident a result must be before RE-call will answer from it. It needs example questions you have not written yet. Come back to it once you have real memory.

You should see, at the end

Output
Calibration skipped. Run recall calibrate later with a labeled query file when you have one.
Wrote .env
Updated CLAUDE.md
Wrote memory\MEMORY.md
Indexed 1 chunks from 1 files in memory

What you now have on disk

.env holds your choices. memory/ is where your memory files go. memory/MEMORY.md is a starter index explaining the file format. CLAUDE.md tells Claude to search memory before it answers, which matters in step 7.

What happens if you answer differently

Answering n to the security question unlocks cloud embedders and offers to store API keys. Those send your text to a third party, which is a decision worth making deliberately rather than during a first install.

Choosing a different embedder changes the vector width. On a fresh database the wizard simply prepares the tables at whatever width you picked. On a database that already holds memory at another width it will not silently rebuild it: rather than failing later, it refuses and stops. It does not re-ask, and it names no command. Choose an embedder matching the existing schema, or point setup at a fresh table name or database.

You can re-run setup at any time. It rewrites only its own block in .env, so anything you added yourself survives.

Wizard exited early, or looped on the embedder question? Setup wizard problems.

04

Let it answer you

One line to add to .env. Skip it and your first search will fail with a Python error rather than a useful message, so do it now.

Add-Content .env "RECALL_TRUST_MODE=development"

This is the step people miss

Out of the box RE-call refuses to answer from a corpus whose confidence threshold has never been measured. That is deliberate: it is the whole point of the product. But you have not measured one yet, so without this line every search stops. Development mode says "I know this threshold is a placeholder, show me the results anyway", and every result you get back will be stamped as uncertified so you cannot forget.

What you are trading away, and how to get it back

In development mode RE-call falls back to a demonstration threshold that is bound to no tenant, no generation and no corpus. It is a placeholder chosen to let you see the machinery work, not a measurement of your data. Every search prints a warning saying exactly that, and every result is tagged DEGRADED with the reason. On a fresh install the reason is INDEX_NOT_READY, because no immutable generation has been built yet; CALIBRATION_MISSING is the related code you see once that part is in place but the threshold still has not been measured.

Measuring a threshold against your own corpus is the calibration page, and it is worth doing once your memory holds something you care about being right. Read that page before you remove this line: leaving development mode needs more than running the calibration command once.

05

Give it a memory

A memory is a markdown file. Save this one as memory/rate-limits.md, in the memory/ folder the wizard created.

memory/rate-limits.md
---
name: api-rate-limit
description: The request ceiling we agreed for the public API.
metadata:
  type: project
---

Clients may issue 100 requests per minute against the public API.
We agreed this on 12 August 2026, after the load test showed the
gateway degrading above 140. Bursts up to 150 are tolerated for
10 seconds before throttling starts.

Then load it into the database.

python -m recall.cli index memory/

You should see

Output
indexed 1 chunks from 1 files, 1 unchanged

What "1 unchanged" means

The wizard already indexed memory/MEMORY.md when it created the folder, and that file has not changed since, so this run skips it. The one new chunk is your rate-limit note. Re-running index only does work for files that actually changed, which is why it is safe to run again whenever you edit something.

What indexing actually does to your file

RE-call reads the markdown, splits it into chunks of a few sentences, converts each chunk into a vector using the local model, and stores the text and the vector together. Searching later compares your question against those vectors to find text that means something similar, which is why it can answer a question phrased quite differently from the note.

The block at the top between the dashes is frontmatter. name and description help you find the file again, and type records what kind of memory it is. Re-running index after editing a file updates it rather than duplicating it.

Dimension mismatch, or nothing indexed? Indexing problems.

06

Ask, and watch it refuse

Two questions. The first is answerable from what you just indexed. The second is not, and what RE-call does with it is the reason the project exists.

python -m recall.cli search "how many requests per minute can a client make?"

You should see something like

Output
[development] using an UNCERTIFIED demonstration threshold of 0.5. This is not a
calibration: it is bound to no tenant, generation or corpus, and production
refuses rather than assuming it.
[DEGRADED:INDEX_NOT_READY] query='how many requests per minute can a client make?'
  index: embedding=bge-small-symmetric-v1 retrieval=legacy generation=legacy
  ok             conf=1.00 cos=0.802  rate-limits.md  'Clients may issue 100 requests per minute against th'
                 chunk_id='cdf9da4656aa6aef8b0af6a739d63fe2' ordinal=0 valid_from=-

Notice that you asked about "requests per minute" and the note says "issue 100 requests per minute". It matched on meaning, not on the words. The DEGRADED tag is expected here and is not an error: it is RE-call recording that it is running on a placeholder threshold rather than one measured on your corpus.

Now ask something your memory has no answer to at all.

python -m recall.cli search "how do we handle penguins on Mars?"

You should see an abstention

Output
[ABSTAIN GAP DEGRADED:INDEX_NOT_READY] query='how do we handle penguins on Mars?'
  index: embedding=bge-small-symmetric-v1 retrieval=legacy generation=legacy
  reason: no hit above the calibrated confidence threshold (probable corpus gap)
  low_confidence conf=0.30 cos=0.458  rate-limits.md  'Clients may issue 100 requests per minute against th'
                 chunk_id='cdf9da4656aa6aef8b0af6a739d63fe2' ordinal=0 valid_from=-

That refusal is the feature

Your rate-limit note is still the closest thing in the corpus to that question, and an ordinary vector search would have handed it back as the answer. Closest is not the same as correct. RE-call scored it, found nothing clearing the threshold, and abstained instead. Note that the note is still listed, marked low_confidence: you are told what was found and why it was not good enough, rather than being given a bare refusal.

Try a harder question, and watch this get less impressive

Ask what is our refund policy? instead and you will probably not get an abstention. On a corpus this small that question scores about 0.58 against the rate-limit note, which clears the placeholder threshold of 0.5, so RE-call answers with a note that has nothing to do with refunds.

That is not a bug, and it is worth understanding before you trust this on real material. The threshold in use was not measured on your corpus; it is a demonstration value. Deciding where that line actually belongs, for your data and your embedder, is what calibration does. Until then, expect the boundary between answering and abstaining to be approximate.

Your install works. What follows is optional, and this is a reasonable place to stop and go fill your memory with real material.

07

Connect Claude Code

This turns your memory into a tool Claude can call by itself, so it checks what you have already decided before it answers, instead of you pasting context into a chat.

First add the server component.

python -m pip install "recall-rag[fastembed,mcp]"

Then save this as .mcp.json, in the same folder as your .env.

.mcp.json
{
  "mcpServers": {
    "recall": {
      "command": "python",
      "args": ["-m", "recall_mcp.server"],
      "env": {
        "RECALL_SERVING_DSN": "postgresql://recall:recall@localhost:5432/recall",
        "RECALL_TENANT": "default",
        "RECALL_TRUST_MODE": "development"
      }
    }
  }
}

The settings have to be repeated here

The MCP server does not read your .env file. That is why the connection string and the development mode appear again inside this JSON. On macOS and Linux, change "command": "python" to "python3".

Confirm Claude can see it

Start Claude Code in that folder and ask it to list its tools, or run /mcp. You are looking for a server named recall offering recall_search, recall_index and recall_stats among others.

What Claude will now do differently

The CLAUDE.md the wizard wrote tells Claude to call recall_search before answering questions about your project, to respect an abstention rather than guessing around it, and to write durable facts into memory/ as it learns them. That last part is what makes the memory grow without you maintaining it by hand.

There is more to this than one step can hold: what each tool returns, how to make Claude cite its evidence, and how to stop it writing junk into your corpus. That is the Claude Code page.

Server not appearing in Claude? Claude Code problems.

Where to go from here