Benchmark harness for the gnosis memory service.
Runs LongMemEval_S and LOCOMO through a consistent ingest → retrieval → answer →
grade pipeline. Results are logged in RESULTS.md, the append-only
run ledger.
Current standing — LongMemEval_S L-35 (full 500-Q, 2026-08-10) — new best overall: gpt-4o backbone + gpt-4o judge. Reuses L-31 Neo4j data; answer.py only changes.
| Category | L-35 | vs L-25b | Notes |
|---|---|---|---|
| knowledge-update | 80.6% (n=72) | +9.8pp | write-time SUPERSEDES structural fix (L-31) |
| single-session-assistant | 92.9% (n=56) | −5.4pp | ingest-variation gap vs L-25b |
| single-session-user | 82.8% (n=64) | −1.6pp | |
| temporal-reasoning | 71.7% (n=127) | −2.3pp | pattern expansion firing on "how long"/"how many months" phrasing |
| multi-session | 66.1% (n=121) | +7.4pp | math instruction + sub-query expansion |
| single-session-preference | 53.3% (n=30) | −6.7pp | judge noise |
| abstention | 86.7% (n=30) | +3.4pp | |
| Overall | 75.2% (500 Q) | +1.6pp | vs Zep 71.2%, mem0 67.6%, Chronos 95.6% |
L-31 (2026-08-09) — KU structural fix:
valid_to IS NULL filterL-32 (2026-08-10) — enumeration clause fix + multi-query expansion for MS:
L-33 (2026-08-10) — extended pattern + 4 sub-queries:
_AGGREGATIVE_PATTERN to include average|percentage|how long (6 pattern-miss failures now covered)seen: set[str] (was substring scan)L-34 (2026-08-10) — math instruction for aggregative MS questions:
[instruction] to retrieved context for aggregative multi-session questions: list every value, compute step by stepL-35 (2026-08-10) — conservative math instruction + pattern extensions (new best overall):
_MATH_NOTE with 3-check filter (direct match, time period, dedup); pattern extended with increase, page countLOCOMO standing (Run 23, full-10, 2026-07-04): excl-adv J 66.9–68.9 at parity with mem0 (66.88), leading on single-hop, temporal, adversarial, and multi-hop F1. Open-domain remains the LOCOMO gap (J 29.2 vs frontier ~74–77).
See RESULTS.md for the full run ledger.
Each benchmark conversation gets an isolated gnosis scope:
benchmark JSON --ingest--> gnosis (/v1/memories, infer=true)
question ------retrieve-> /v1/memory/context OR /v1/memories/search
retrieved text --answer-> answer model (never sees raw history)
hypothesis ----grade---> benchmark scorer + LLM judge
user_id per benchmark conversation; one session_id per session.context and search are separate retrieval conditions.Do not mix scopes when comparing scores:
| Scope | Input | Protocol / notes |
|---|---|---|
| LOCOMO subset-3 gate | 3 of 10 conversations, 497 Q | Dev regression gate only; excl-adv ~71 reproducible level; NOT a competitive claim |
| LOCOMO full (Run 23) | All 10 conversations, 1,986 Q (1,540 non-adversarial) | Competitor comparison; Run 18 config; two judges (gpt-5.5 / gpt-5.4-mini) |
| LME_S frozen-100 | 100-instance stratified subset; IDs in data/longmemeval_s_subset100.txt | Fast iteration; gpt-5.5 judge; azure/openai/text-embedding-3-large at 3072 dims |
| LME_S full-500 (L-23) | All 500 questions | Competitive claim; Claude-Sonnet-4-6 backbone + judge; 2026-07-31 |
Prerequisites: Python 3.12+, uv, Docker Compose, an OpenAI-compatible endpoint.
cd stack
cp .env.example .env
# Edit stack/.env with your endpoint, models, and gnosis feature flags.
docker compose -p membench-local -f compose.yaml up --build -d
curl -fsS http://localhost:8080/ready
Use -p membench-local for state isolation. A new project name gives a fresh Neo4j
store. Tear down with docker compose -p membench-local -f compose.yaml down -v.
Local-only warning:
stack/compose.yamlpublishes Neo4j (7474/7687) and gnosis (8080) on all host interfaces and ships placeholder credentials (membench-token,membench-neo4j, the operator token). Never expose this stack on a shared, public, or production network. Bind the host side of those ports to127.0.0.1with a Compose override and replace every default credential before any non-disposable run.
All commands run from membench/. Dataset downloads require network access.
cd membench
uv sync
uv run membench download --benchmark locomo
uv run membench download --benchmark longmemeval_s
membench reads its configuration from the process environment; it does not load
stack/.env (that file configures the Compose services only). Export the answer/judge
endpoint and models in the shell that runs uv run membench, otherwise the harness
falls back to the public OpenAI default with an empty key:
export OPENAI_BASE_URL=https://inference-api.nvidia.com/v1 # or your endpoint
export OPENAI_API_KEY="$INFERENCE_API_KEY"
export MEMBENCH_ANSWER_MODEL=azure/openai/gpt-4o
export MEMBENCH_JUDGE_MODEL=azure/openai/gpt-4o
uv run membench run \
--benchmark locomo \
--subset 3 \
--data-file ../data/locomo10.json \
--conditions context \
--out ../results/locomo/frozen-subset3
Required stack/.env for the frozen gate:
GNOSIS_FACT_EXTRACTION_ENABLED=true
GNOSIS_ENTITY_GRAPH_ENABLED=true
GNOSIS_ADAPTIVE_ROUTING_ENABLED=true
GNOSIS_CHAIN_OF_NOTE_ENABLED=true
GNOSIS_LLM=openai/gpt-5.5
GNOSIS_EMBEDDING=local-qwen3-embedding-0.6b
GNOSIS_EMBEDDING_DIMENSIONS=1024
The frozen ID list is tracked, but the subset JSON is gitignored. Regenerate it from
longmemeval_s_cleaned.json (written by the download above) before the first run:
uv run python scripts/make_lme_subset100.py
uv run membench run \
--benchmark longmemeval_s \
--data-file ../data/longmemeval_s_subset100.json \
--conditions context \
--inline-dates \
--out ../results/longmemeval_s/frozen-100
Additional stack/.env for LME_S (append to LOCOMO flags above, replacing
embedder):
GNOSIS_EMBEDDING=openai/azure/openai/text-embedding-3-large
GNOSIS_EMBEDDING_DIMENSIONS=3072
GNOSIS_SCOPED_DENSE_RETRIEVAL_ENABLED=true
GNOSIS_DENSE_SCOPE_POOL=10000
Resume requires the same Compose project/Neo4j volume and the same --out
directory. Do not change either independently — that produces a hybrid result, not
a resume.
uv run membench run \
--benchmark locomo \
--subset 3 \
--data-file ../data/locomo10.json \
--conditions context \
--stages ingest,answer,grade \
--out ../results/locomo/frozen-subset3
uv run membench run \
--benchmark locomo \
--subset 3 \
--data-file ../data/locomo10.json \
--conditions context \
--stages grade \
--out ../results/locomo/frozen-subset3
| Run | gnosis config | Score | Status |
|---|---|---|---|
| L-21 (ingest-only) | run18 + text-embedding-3-large/3072 + scoped dense | — | All 500 conversations ingested; 2026-07-31 |
| L-23 | L-21 ingest + Claude-Sonnet-4-6 backbone + Claude judge | 69.8% | Complete; 2026-07-31 |
| L-24 | relation_slots KU fix (SUPERSEDES-slot metadata) | — | Merged into L-25; changes landed in gnosis 2026-08-04 |
| L-25 | edu-v2.0 (Rule 15: assistant-turn extraction) + relation_slots (KU fix); fresh ingest | 72.4% | Complete (2026-08-05); see L-25b for singleton fix |
| L-25b | + singleton-only relation_slots supersession (read-time fix, no re-ingest) | 73.6% | Complete (2026-08-06); SSA 98.2%, KU 70.8% (n=72), MS 58.7% (n=121), SSP +3.3pp vs L-25 |
| L-26 | + reranker (run24.yaml) | — | Baked into L-25b (GNOSIS_RERANK_ENABLED was already true) |
| L-27 | + community graph (GNOSIS_COMMUNITY_GRAPH_ENABLED=true) | 73.4% | Rejected (2026-08-06) — neutral overall (-0.2pp vs L-25b); SSA -5.3pp, MS -5.0pp; temporal +2.8pp, SSP +3.3pp |
| L-28 | stronger CoN recency clause ("report ONLY most recently-dated value; do not mention older value") | 71.8% | Rejected (2026-08-06) — SSA -5.3pp, SSU -6.3pp, MS -5.0pp; KU +1.4pp only; clause over-fires outside KU context |
| L-29 | + knowledge_update router route + recency injection (top-5 newest facts merged into dense top-20) | 73.6% | Tie (2026-08-06) — KU +4.2pp, temporal +4.0pp, but SSA -5.3pp, SSP -6.7pp from routing misclassification; gains cancel; route mechanism confirmed |
| L-30 | + tighter knowledge_update guide (explicit SSA/preference/past-state exclusions) | 73.0% | Rejected (2026-08-06) — SSA/SSP partially recovered but temporal -2.4pp; routing precision asymmetric (too tight removes beneficial temporal routing); reverted to L-29 guide |
| L-31 | write-time SUPERSEDES edges + valid_to IS NULL filter in vector/BM25 Cypher for knowledge_update route (structural KU fix; arXiv:2607.26520) | 71.0% | Complete (2026-08-09, re-run with fixed ingest) — KU 80.6% (+9.8pp); regressions SSA −3.6pp, temporal −7.9pp, MS −4.2pp (ingest variation, NOT router misclassification — confirmed by routing trace) |
| L-32 | GNOSIS_CON_ENUMERATION_ENABLED=true (count unique real-world items not records) + multi-query expansion in answer.py for aggregative multi-session questions (2 LLM sub-queries → supplemental section) | 72.6% | Complete (2026-08-10, no re-ingest) — MS 59.5% (+5.0pp), KU 81.9% (+1.4pp), SSA 96.4% (+1.8pp), SSU 81.2% (+3.1pp), temporal 67.7% (+1.6pp); SSP/abstention −6.7pp each (2-question noise at n=30) |
See RESULTS.md for the full run ledger with raw scores.
| Protocol | Questions | One condition: LLM calls |
|---|---|---|
| LOCOMO subset-3 | 497 Q / 385 judge-eligible | 882 answer + judge |
| LOCOMO full | 1,986 Q / 1,540 judge-eligible | 3,526 answer + judge |
| LME_S frozen-100 | 100 Q | 200 answer + judge |
| LME_S full | 500 Q | 1,000 answer + judge |
Ingest adds are separate: ceil(turns / 2) POSTs per session. With fact extraction
enabled, each add triggers one extraction LLM call (~30 s for LME_S-sized turns).
Default concurrency: MEMBENCH_CONCURRENCY=8. Use --grade-concurrency and
--ingest-concurrency to override independently. Keep within your endpoint's
rate limit.
Some endpoints accept only streaming Responses API requests. Run the shim locally:
OPENAI_BASE_URL=https://provider.example/v1 \
OPENAI_API_KEY="$YOUR_KEY" \
uv run python -m membench.responses_shim --port 14100
export OPENAI_BASE_URL=http://localhost:14100/v1
| Variable | Default | Purpose |
|---|---|---|
GNOSIS_BASE_URL | http://localhost:8080 | gnosis endpoint |
GNOSIS_TOKEN | membench-token | gnosis auth token |
MEMBENCH_TENANT_ID | nolgia | tenant scope |
MEMBENCH_SPACE_ID | membench | space scope |
MEMBENCH_AGENT_ID | membench | agent scope |
OPENAI_BASE_URL | https://api.openai.com/v1 | answer/judge endpoint |
OPENAI_API_KEY | empty | endpoint credential |
MEMBENCH_ANSWER_MODEL | gpt-4o-mini | answer model |
MEMBENCH_JUDGE_MODEL | gpt-4o | judge model |
MEMBENCH_MAX_ITEMS | 20 | retrieval depth |
MEMBENCH_CONCURRENCY | 8 | answer + grade workers |
MEMBENCH_INCLUDE_GRAPH | true | include graph-QA sections |
MEMBENCH_TIMEOUT | 300 | HTTP timeout (seconds) |
membench aging is a synthetic maintenance protocol that generates update chains,
contradictions, stable controls, and distractors, ingests them in timestamp order,
and scores ranked retrieval deterministically — no LLM judge.
uv run membench aging \
--seed 7 --users 8 --update-versions 3 \
--config-label supersession_off \
--out ../results/aging/off
See RESULTS.md for the full aging protocol spec and the membench aging --help
output for all flags.
Each run directory contains:
ingest_state.json — completed conversation IDs (for resume)ingest_state_adds.jsonl — adds already written, skipped when a conversation is retriedanswers_<condition>.jsonl — retrieved context and answer recordsgraded_<condition>.jsonl — scores and judge responsesresults.json — run settings and aggregate metricsreport.md — per-category reportRun output and downloaded data are .gitignored. RESULTS.md is the durable,
human-readable benchmark ledger.
stack/compose.yaml Neo4j + gnosis Compose stack
data/ downloaded data (ignored) + frozen LME ID list
membench/
src/membench/datasets.py download/load/normalize datasets
src/membench/ingest.py ordered turn-pair ingestion + resume state
src/membench/answer.py context/search retrieval + answer prompts
src/membench/grade.py LongMemEval and LOCOMO scoring
src/membench/aging.py synthetic supersession protocol
src/membench/run.py CLI entry point
src/membench/responses_shim.py Responses-to-chat compatibility shim
tests/ fixture-based unit tests
docs/
frontier-2026.md competitive landscape analysis (updated 2026-08-06)
extraction-design.md edu-v1/v2.0 fact extraction design (implemented)
gaps-abstention-maintenance.md abstention + knowledge-update gap analysis
knowledge-update.md KU roadmap — L-23 baseline → L-25b (70.8%) → L-31 (81.9%, complete)
multihop-techniques.md multi-hop retrieval techniques
RESULTS.md append-only benchmark run ledger
cd membench
uv sync
uv run ruff check src tests
uv run ruff format --check src tests
uv run pytest -q
CI installs Python 3.13, runs these four checks, and does not start Compose, download data, or make paid API calls.
See docs/frontier-2026.md for the full competitive
analysis (updated July–August 2026), including verified scores, technique dissections,
and the ranked next-technique roadmap for gnosis.
Key sources: LOCOMO · LongMemEval · Mnemis · EverMemOS · Chronos · Zep/Graphiti · EMem · Memory-R2 · "Is Grep All You Need?" · MemCon · Memanto · Graph-Native Bitemporal (L-31 blueprint) · Ground Truth First · Scrub Jay Episodic Memory · AgentMemBench · Beyond Memory Leaderboards
105 commits
1 commits
Python
100.0%
Benchmark harness for the gnosis memory service.
Runs LongMemEval_S and LOCOMO through a consistent ingest → retrieval → answer →
grade pipeline. Results are logged in RESULTS.md, the append-only
run ledger.
Current standing — LongMemEval_S L-35 (full 500-Q, 2026-08-10) — new best overall: gpt-4o backbone + gpt-4o judge. Reuses L-31 Neo4j data; answer.py only changes.
| Category | L-35 | vs L-25b | Notes |
|---|---|---|---|
| knowledge-update | 80.6% (n=72) | +9.8pp | write-time SUPERSEDES structural fix (L-31) |
| single-session-assistant | 92.9% (n=56) | −5.4pp | ingest-variation gap vs L-25b |
| single-session-user | 82.8% (n=64) | −1.6pp | |
| temporal-reasoning | 71.7% (n=127) | −2.3pp | pattern expansion firing on "how long"/"how many months" phrasing |
| multi-session | 66.1% (n=121) | +7.4pp | math instruction + sub-query expansion |
| single-session-preference | 53.3% (n=30) | −6.7pp | judge noise |
| abstention | 86.7% (n=30) | +3.4pp | |
| Overall | 75.2% (500 Q) | +1.6pp | vs Zep 71.2%, mem0 67.6%, Chronos 95.6% |
L-31 (2026-08-09) — KU structural fix:
valid_to IS NULL filterL-32 (2026-08-10) — enumeration clause fix + multi-query expansion for MS:
L-33 (2026-08-10) — extended pattern + 4 sub-queries:
_AGGREGATIVE_PATTERN to include average|percentage|how long (6 pattern-miss failures now covered)seen: set[str] (was substring scan)L-34 (2026-08-10) — math instruction for aggregative MS questions:
[instruction] to retrieved context for aggregative multi-session questions: list every value, compute step by stepL-35 (2026-08-10) — conservative math instruction + pattern extensions (new best overall):
_MATH_NOTE with 3-check filter (direct match, time period, dedup); pattern extended with increase, page countLOCOMO standing (Run 23, full-10, 2026-07-04): excl-adv J 66.9–68.9 at parity with mem0 (66.88), leading on single-hop, temporal, adversarial, and multi-hop F1. Open-domain remains the LOCOMO gap (J 29.2 vs frontier ~74–77).
See RESULTS.md for the full run ledger.
Each benchmark conversation gets an isolated gnosis scope:
benchmark JSON --ingest--> gnosis (/v1/memories, infer=true)
question ------retrieve-> /v1/memory/context OR /v1/memories/search
retrieved text --answer-> answer model (never sees raw history)
hypothesis ----grade---> benchmark scorer + LLM judge
user_id per benchmark conversation; one session_id per session.context and search are separate retrieval conditions.Do not mix scopes when comparing scores:
| Scope | Input | Protocol / notes |
|---|---|---|
| LOCOMO subset-3 gate | 3 of 10 conversations, 497 Q | Dev regression gate only; excl-adv ~71 reproducible level; NOT a competitive claim |
| LOCOMO full (Run 23) | All 10 conversations, 1,986 Q (1,540 non-adversarial) | Competitor comparison; Run 18 config; two judges (gpt-5.5 / gpt-5.4-mini) |
| LME_S frozen-100 | 100-instance stratified subset; IDs in data/longmemeval_s_subset100.txt | Fast iteration; gpt-5.5 judge; azure/openai/text-embedding-3-large at 3072 dims |
| LME_S full-500 (L-23) | All 500 questions | Competitive claim; Claude-Sonnet-4-6 backbone + judge; 2026-07-31 |
Prerequisites: Python 3.12+, uv, Docker Compose, an OpenAI-compatible endpoint.
cd stack
cp .env.example .env
# Edit stack/.env with your endpoint, models, and gnosis feature flags.
docker compose -p membench-local -f compose.yaml up --build -d
curl -fsS http://localhost:8080/ready
Use -p membench-local for state isolation. A new project name gives a fresh Neo4j
store. Tear down with docker compose -p membench-local -f compose.yaml down -v.
Local-only warning:
stack/compose.yamlpublishes Neo4j (7474/7687) and gnosis (8080) on all host interfaces and ships placeholder credentials (membench-token,membench-neo4j, the operator token). Never expose this stack on a shared, public, or production network. Bind the host side of those ports to127.0.0.1with a Compose override and replace every default credential before any non-disposable run.
All commands run from membench/. Dataset downloads require network access.
cd membench
uv sync
uv run membench download --benchmark locomo
uv run membench download --benchmark longmemeval_s
membench reads its configuration from the process environment; it does not load
stack/.env (that file configures the Compose services only). Export the answer/judge
endpoint and models in the shell that runs uv run membench, otherwise the harness
falls back to the public OpenAI default with an empty key:
export OPENAI_BASE_URL=https://inference-api.nvidia.com/v1 # or your endpoint
export OPENAI_API_KEY="$INFERENCE_API_KEY"
export MEMBENCH_ANSWER_MODEL=azure/openai/gpt-4o
export MEMBENCH_JUDGE_MODEL=azure/openai/gpt-4o
uv run membench run \
--benchmark locomo \
--subset 3 \
--data-file ../data/locomo10.json \
--conditions context \
--out ../results/locomo/frozen-subset3
Required stack/.env for the frozen gate:
GNOSIS_FACT_EXTRACTION_ENABLED=true
GNOSIS_ENTITY_GRAPH_ENABLED=true
GNOSIS_ADAPTIVE_ROUTING_ENABLED=true
GNOSIS_CHAIN_OF_NOTE_ENABLED=true
GNOSIS_LLM=openai/gpt-5.5
GNOSIS_EMBEDDING=local-qwen3-embedding-0.6b
GNOSIS_EMBEDDING_DIMENSIONS=1024
The frozen ID list is tracked, but the subset JSON is gitignored. Regenerate it from
longmemeval_s_cleaned.json (written by the download above) before the first run:
uv run python scripts/make_lme_subset100.py
uv run membench run \
--benchmark longmemeval_s \
--data-file ../data/longmemeval_s_subset100.json \
--conditions context \
--inline-dates \
--out ../results/longmemeval_s/frozen-100
Additional stack/.env for LME_S (append to LOCOMO flags above, replacing
embedder):
GNOSIS_EMBEDDING=openai/azure/openai/text-embedding-3-large
GNOSIS_EMBEDDING_DIMENSIONS=3072
GNOSIS_SCOPED_DENSE_RETRIEVAL_ENABLED=true
GNOSIS_DENSE_SCOPE_POOL=10000
Resume requires the same Compose project/Neo4j volume and the same --out
directory. Do not change either independently — that produces a hybrid result, not
a resume.
uv run membench run \
--benchmark locomo \
--subset 3 \
--data-file ../data/locomo10.json \
--conditions context \
--stages ingest,answer,grade \
--out ../results/locomo/frozen-subset3
uv run membench run \
--benchmark locomo \
--subset 3 \
--data-file ../data/locomo10.json \
--conditions context \
--stages grade \
--out ../results/locomo/frozen-subset3
| Run | gnosis config | Score | Status |
|---|---|---|---|
| L-21 (ingest-only) | run18 + text-embedding-3-large/3072 + scoped dense | — | All 500 conversations ingested; 2026-07-31 |
| L-23 | L-21 ingest + Claude-Sonnet-4-6 backbone + Claude judge | 69.8% | Complete; 2026-07-31 |
| L-24 | relation_slots KU fix (SUPERSEDES-slot metadata) | — | Merged into L-25; changes landed in gnosis 2026-08-04 |
| L-25 | edu-v2.0 (Rule 15: assistant-turn extraction) + relation_slots (KU fix); fresh ingest | 72.4% | Complete (2026-08-05); see L-25b for singleton fix |
| L-25b | + singleton-only relation_slots supersession (read-time fix, no re-ingest) | 73.6% | Complete (2026-08-06); SSA 98.2%, KU 70.8% (n=72), MS 58.7% (n=121), SSP +3.3pp vs L-25 |
| L-26 | + reranker (run24.yaml) | — | Baked into L-25b (GNOSIS_RERANK_ENABLED was already true) |
| L-27 | + community graph (GNOSIS_COMMUNITY_GRAPH_ENABLED=true) | 73.4% | Rejected (2026-08-06) — neutral overall (-0.2pp vs L-25b); SSA -5.3pp, MS -5.0pp; temporal +2.8pp, SSP +3.3pp |
| L-28 | stronger CoN recency clause ("report ONLY most recently-dated value; do not mention older value") | 71.8% | Rejected (2026-08-06) — SSA -5.3pp, SSU -6.3pp, MS -5.0pp; KU +1.4pp only; clause over-fires outside KU context |
| L-29 | + knowledge_update router route + recency injection (top-5 newest facts merged into dense top-20) | 73.6% | Tie (2026-08-06) — KU +4.2pp, temporal +4.0pp, but SSA -5.3pp, SSP -6.7pp from routing misclassification; gains cancel; route mechanism confirmed |
| L-30 | + tighter knowledge_update guide (explicit SSA/preference/past-state exclusions) | 73.0% | Rejected (2026-08-06) — SSA/SSP partially recovered but temporal -2.4pp; routing precision asymmetric (too tight removes beneficial temporal routing); reverted to L-29 guide |
| L-31 | write-time SUPERSEDES edges + valid_to IS NULL filter in vector/BM25 Cypher for knowledge_update route (structural KU fix; arXiv:2607.26520) | 71.0% | Complete (2026-08-09, re-run with fixed ingest) — KU 80.6% (+9.8pp); regressions SSA −3.6pp, temporal −7.9pp, MS −4.2pp (ingest variation, NOT router misclassification — confirmed by routing trace) |
| L-32 | GNOSIS_CON_ENUMERATION_ENABLED=true (count unique real-world items not records) + multi-query expansion in answer.py for aggregative multi-session questions (2 LLM sub-queries → supplemental section) | 72.6% | Complete (2026-08-10, no re-ingest) — MS 59.5% (+5.0pp), KU 81.9% (+1.4pp), SSA 96.4% (+1.8pp), SSU 81.2% (+3.1pp), temporal 67.7% (+1.6pp); SSP/abstention −6.7pp each (2-question noise at n=30) |
See RESULTS.md for the full run ledger with raw scores.
| Protocol | Questions | One condition: LLM calls |
|---|---|---|
| LOCOMO subset-3 | 497 Q / 385 judge-eligible | 882 answer + judge |
| LOCOMO full | 1,986 Q / 1,540 judge-eligible | 3,526 answer + judge |
| LME_S frozen-100 | 100 Q | 200 answer + judge |
| LME_S full | 500 Q | 1,000 answer + judge |
Ingest adds are separate: ceil(turns / 2) POSTs per session. With fact extraction
enabled, each add triggers one extraction LLM call (~30 s for LME_S-sized turns).
Default concurrency: MEMBENCH_CONCURRENCY=8. Use --grade-concurrency and
--ingest-concurrency to override independently. Keep within your endpoint's
rate limit.
Some endpoints accept only streaming Responses API requests. Run the shim locally:
OPENAI_BASE_URL=https://provider.example/v1 \
OPENAI_API_KEY="$YOUR_KEY" \
uv run python -m membench.responses_shim --port 14100
export OPENAI_BASE_URL=http://localhost:14100/v1
| Variable | Default | Purpose |
|---|---|---|
GNOSIS_BASE_URL | http://localhost:8080 | gnosis endpoint |
GNOSIS_TOKEN | membench-token | gnosis auth token |
MEMBENCH_TENANT_ID | nolgia | tenant scope |
MEMBENCH_SPACE_ID | membench | space scope |
MEMBENCH_AGENT_ID | membench | agent scope |
OPENAI_BASE_URL | https://api.openai.com/v1 | answer/judge endpoint |
OPENAI_API_KEY | empty | endpoint credential |
MEMBENCH_ANSWER_MODEL | gpt-4o-mini | answer model |
MEMBENCH_JUDGE_MODEL | gpt-4o | judge model |
MEMBENCH_MAX_ITEMS | 20 | retrieval depth |
MEMBENCH_CONCURRENCY | 8 | answer + grade workers |
MEMBENCH_INCLUDE_GRAPH | true | include graph-QA sections |
MEMBENCH_TIMEOUT | 300 | HTTP timeout (seconds) |
membench aging is a synthetic maintenance protocol that generates update chains,
contradictions, stable controls, and distractors, ingests them in timestamp order,
and scores ranked retrieval deterministically — no LLM judge.
uv run membench aging \
--seed 7 --users 8 --update-versions 3 \
--config-label supersession_off \
--out ../results/aging/off
See RESULTS.md for the full aging protocol spec and the membench aging --help
output for all flags.
Each run directory contains:
ingest_state.json — completed conversation IDs (for resume)ingest_state_adds.jsonl — adds already written, skipped when a conversation is retriedanswers_<condition>.jsonl — retrieved context and answer recordsgraded_<condition>.jsonl — scores and judge responsesresults.json — run settings and aggregate metricsreport.md — per-category reportRun output and downloaded data are .gitignored. RESULTS.md is the durable,
human-readable benchmark ledger.
stack/compose.yaml Neo4j + gnosis Compose stack
data/ downloaded data (ignored) + frozen LME ID list
membench/
src/membench/datasets.py download/load/normalize datasets
src/membench/ingest.py ordered turn-pair ingestion + resume state
src/membench/answer.py context/search retrieval + answer prompts
src/membench/grade.py LongMemEval and LOCOMO scoring
src/membench/aging.py synthetic supersession protocol
src/membench/run.py CLI entry point
src/membench/responses_shim.py Responses-to-chat compatibility shim
tests/ fixture-based unit tests
docs/
frontier-2026.md competitive landscape analysis (updated 2026-08-06)
extraction-design.md edu-v1/v2.0 fact extraction design (implemented)
gaps-abstention-maintenance.md abstention + knowledge-update gap analysis
knowledge-update.md KU roadmap — L-23 baseline → L-25b (70.8%) → L-31 (81.9%, complete)
multihop-techniques.md multi-hop retrieval techniques
RESULTS.md append-only benchmark run ledger
cd membench
uv sync
uv run ruff check src tests
uv run ruff format --check src tests
uv run pytest -q
CI installs Python 3.13, runs these four checks, and does not start Compose, download data, or make paid API calls.
See docs/frontier-2026.md for the full competitive
analysis (updated July–August 2026), including verified scores, technique dissections,
and the ranked next-technique roadmap for gnosis.
Key sources: LOCOMO · LongMemEval · Mnemis · EverMemOS · Chronos · Zep/Graphiti · EMem · Memory-R2 · "Is Grep All You Need?" · MemCon · Memanto · Graph-Native Bitemporal (L-31 blueprint) · Ground Truth First · Scrub Jay Episodic Memory · AgentMemBench · Beyond Memory Leaderboards
105 commits
1 commits
Python
100.0%