Agent memory that shows its sources

memspine keeps each agent's conversation turns, tool calls and conclusions in a separate database for every customer. It returns a conclusion with the events it came from and erases any event from disk on request. It runs as one binary in your own infrastructure.

POST /v1/memory/events POST /v1/memory/recall {"text":"vet appointment booking","k":2} POST /v1/memory/recall {"text":"vet appointment booking","k":2,"hops":1} DELETE /v1/memory/event/af2d5cc8...?purge=true
  1. turnAna: we adopted a greyhound called Pixel last weekend
  2. turnAna: she needs a vet, somewhere open on Saturdays
  3. tool_callfind_vets(city=Lisbon, open=saturday) -> Clinica Arroios, VetLuz
  4. turnAna: book Clinica Arroios for this Saturday at tensource
  5. tool_callbook_vet(Clinica Arroios, 2026-10-10 10:00) -> confirmed A-2291source
  6. factAna owns a greyhound named Pixel
  7. factAna prefers Saturday appointments
  8. factPixel has a vet appointment at Clinica Arroios on 2026-10-10 at 10:00, booking A-2291#13.2165answer
  9. turnAna: my number is 912 555 019, text me the day beforedeleted
  10. factText Ana the day before the vet appointment#22.5492answerkept

One agent session as memspine stored it: the customer's turns, the agent's tool calls and the facts it concluded. The lines at the left tie each conclusion to the events it came from. Eight of the ten arrived in the two requests below, the last two in one request each.

$ curl -s localhost:7777/v1/memory/events -H "$K" -H "$J" -d @turns.json; echo
{"event_ids":["75173310-8a48-40bc-8b49-8c2ab8c7dc0c","9509bd23-a670-42e0-bbe0-b87e994b0617","697ea0fa-fa50-4d51-9aa8-417263290f08","b8533f46-b491-4c20-a078-b0ca2e039926","740c7d03-9b97-4854-8799-6d66524cf3fe"]}

$ curl -s localhost:7777/v1/memory/events -H "$K" -H "$J" -d @facts.json; echo
{"event_ids":["d53b6b8b-5c0e-4785-982b-db4f145dd1d9","b41bdb35-2dcc-4452-af6e-2dba054958ce","3dce87e5-4b2c-4cc0-96bc-338ce95f158f"]}

Ask in words, by meaning, or both. This request asks in words for the top two of the ten events and gets them back ranked.

$ curl -s localhost:7777/v1/memory/recall -H "$K" -H "$J" \
  -d '{"text":"vet appointment booking","k":2}' \
  | jq -r '.hits[] | [(.score*1e4|round/1e4), .kind, .event_id[0:8], .text[0:44]] | @tsv'
3.2165	fact	3dce87e5	Pixel has a vet appointment at Clinica Arroi
2.5492	fact	c3d7a7af	Text Ana the day before the vet appointment

The same question, with its sources. The first answer comes back with the customer's instruction and the tool call it was derived from, so a reviewer can see what the agent knew. A request adds at most k source events, and this one asked for two.

$ curl -s localhost:7777/v1/memory/recall -H "$K" -H "$J" \
  -d '{"text":"vet appointment booking","k":2,"hops":1}' \
  | jq -r '.hits[] | [.kind, .event_id[0:8], (.via // "-")[0:8], .text[0:52]] | @tsv'
fact	3dce87e5	-	Pixel has a vet appointment at Clinica Arroios on 20
fact	c3d7a7af	-	Text Ana the day before the vet appointment
turn	b8533f46	3dce87e5	Ana: book Clinica Arroios for this Saturday at ten
tool_call	740c7d03	3dce87e5	book_vet(Clinica Arroios, 2026-10-10 10:00) -> confi

The customer asks for their phone number to be removed. One request deletes the event from every answer and from the files on disk; the search of the data directory that follows finds nothing.

$ grep -rl "912 555 019" data
data/00000000-0000-0000-0000-000000000042/events.ffs.qlog

$ curl -s -X DELETE "localhost:7777/v1/memory/event/$E9?purge=true" -H "$K"; echo
{"deleted":true,"purged":true}

$ grep -rl "912 555 019" data; echo "grep exit $?"
grep exit 1

A real session against memspine 0.2.2. The full transcript has every request and response.

88.9%

of the evidence found on LoCoMo, a public benchmark, at 20 results per query with client-side fact extraction; 79.4% on raw turns

2.8 ms

median time to search a customer's 10,000 stored events

0

confirmed writes lost when the server is killed; every write is on disk before the reply

60 s

default interval between purge passes, which rewrite a customer's files without its deleted events

How each figure was measured, and where the numbers are weaker, is on the results page.

What it gives a business

How each operation works ->
turnAna: book Clinica Arroios for this Saturday at ten
tool_callbook_vet(Clinica Arroios, 2026-10-10 10:00) -> confirmed A-2291
factPixel has a vet appointment at Clinica Arroios on 2026-10-10 at 10:00, booking A-2291

An answer you can trace

When an agent states something, the fact it relied on links to the conversation turns and tool calls it was derived from. One request returns the hits and up to k of the events they were derived from.

Your infrastructure

One server binary for Linux or macOS. No other services to run. The server makes no outbound network calls.

Each customer kept apart

Every customer is a separate database with its own keys and limits. A key reads and writes one customer's memory.

turnAna: my number is 912 555 019, text me the day before
$ grep -rl "912 555 019" data; echo "grep exit $?"
grep exit 1

Deletion that reaches the disk

Forgetting an event removes it from every answer at once. Its bytes leave the files on disk at the next purge, which runs every 60 seconds by default, or before the reply when the request asks for it. The tests check that the bytes are gone.

turnAna: thanks, that is all for today

Nothing confirmed is lost

A write is on disk before the server replies. In the recorded session the server is stopped with kill -9, started again, and returns the last event it had confirmed.

Customer support agents

Keep each customer's history across sessions. When a case is escalated, show what the agent was told and what it looked up before it answered.

Operations agents

Record every action an agent takes in your systems together with the instruction and the data behind it, so the action can be audited later.

Assistants with long-running work

Carry what an assistant learned in one session into the next without replaying whole transcripts into the prompt.

Retrieval is scored on LoCoMo: 1,540 questions over 10 long conversations, of which 1,536 name evidence to find. The score is the share of that evidence among the events returned, 20 per query.

With the client extracting facts and rewriting each question into as many as four queries, as the benchmark harness does, memspine retrieves 0.889 of the evidence. Storing raw turns and sending the question as it is, 0.794.

End to end, with a model answering from the retrieved events and a judge marking it under a published rubric, 0.786 of answers were accepted in a June run on an earlier version of the engine.

with client-side extractionraw turns
keyword only
0.812
0.587
embedding only
0.869
0.787
both, fused
0.889
0.794

Evidence recall on LoCoMo at 20 results per query, 10 conversations, 1,536 scored questions, text-embedding-3-small at 384 dimensions.

install
$ curl -fsSL https://memspine.com/install.sh | sh
Downloading memspine-macos-arm64.tar.gz ...
Checksum OK.
Installed memspine-server and memspine-admin to ~/.local/bin

Start the server:
  MEMSPINE_BIND=127.0.0.1:7777 ~/.local/bin/memspine-server
  • Version 0.2.2 for Linux x86_64 (built for glibc 2.17; run after each release on AlmaLinux 8 and Ubuntu) and macOS arm64.
  • The server and its admin tool, memspine-admin, in ~/.local/bin, checked against a published checksum.
  • No root.
  • As installed, any UUID is a customer and its own key, which is for local use. memspine-admin init turns on issued keys.
first event, first recall
$ MEMSPINE_BIND=127.0.0.1:7777 MEMSPINE_EMBEDDING_DIM=4 \
    ~/.local/bin/memspine-server > memspine.log 2>&1 &
$ sleep 1; curl localhost:7777/health
{"service":"memspine-server","status":"ok","version":"0.2.2"}

$ K="Authorization: Bearer 00000000-0000-0000-0000-000000000042"
$ J="Content-Type: application/json"

$ TURN=$(curl -s localhost:7777/v1/memory/event -H "$K" -H "$J" \
  -d '{"kind":"turn","embedding":[0.9,0.1,0.2,0.1],
    "text":"Ana: we adopted a greyhound called Pixel last weekend"
    }' | jq -r .event_id)

$ curl -s localhost:7777/v1/memory/event -H "$K" -H "$J" \
  -d '{"kind":"fact","embedding":[0.8,0.2,0.1,0.1],
    "text":"Ana owns a dog named Pixel","properties":{
    "source_event_ids":["'"$TURN"'"]}}'
{"event_id":"b5ea3003-7681-4632-a015-5ec4fdec7595"}

$ curl -s localhost:7777/v1/memory/recall -H "$K" -H "$J" \
  -d '{"text":"which dog does Ana have","k":1,"hops":1}' \
  | jq -c '.hits[] | [.kind, .text]'
["fact","Ana owns a dog named Pixel"]
["turn","Ana: we adopted a greyhound called Pixel last weekend"]

How it is checked

162 automated tests

Every change runs these, the linters and a container that is started and written through. The Python and TypeScript SDK suites hold 50 more and are not part of that run.

2 releases of fixes from an independent review

An independent review of 0.1.0 and 0.2.0 went looking for defects. 0.2.1 and 0.2.2 are the fixes, and the changelog lists each one.

3 systems the installer is run on

After every release the install command is run on Ubuntu, AlmaLinux 8 and macOS, and the installed binaries store, recall and delete an event.

What has broken, and when ->

What it does not do

It does not call an embedding model or a language model. Your application supplies embeddings and decides what to store.

It keeps one copy of the data on one machine. There is no replication yet.

Search compares against every stored embedding, which suits a customer with up to about 100,000 events.

It speaks plain HTTP. Put TLS in front of it with a reverse proxy.

All limits ->
Early access

Join the waitlist

Tell us which agents you would give memory, and we will be in touch when there is room for your team.

The form needs JavaScript. Open the early access form instead.

Running agents for your customers?

memspine is built by ERP.AI. If you are putting memory under agents that serve your customers, talk to us.