Skip to main content

hotmemory

Agent memory as tables on Hotdata.

A memory record is a row in a managed table. The row carries the text, a scope, tags, source references, and the time span in which the fact was true. The table is an ordinary Hotdata table, so an agent can join its memory to its own data in one SQL query. None of the memory systems that we surveyed stores memory as typed columns in the same engine as the data of the consumer.

Status: alpha. A minor version before 1.0 can change a public surface, and CHANGELOG.md lists each change. The storage contract exists in Python with two drivers. MemoryStore runs in process memory. HotdataStore keeps records in one Hotdata managed database. The memory contract, Memory, runs over either driver.

The library has two layers:

  • A storage contract. Put, get, list, search, and delete records in a namespace. Records are immutable. A new put under the same key creates a new revision.
  • A memory contract. Remember facts, recall them inside a context budget, supersede a fact, forget by id or by horizon, and load the profile of a subject. Extraction from raw text is optional, and it takes an extractor callable that the caller supplies. load cuts a Markdown document into chunks, stores each chunk as an episode, and extracts facts that name their episode as a source. capture with an episode key stores its text as an episode in the same way, or as chunks with chunk_chars. profile returns facts, profiles, and procedures, never episodes. recall returns them too, and adds episodes after the facts only when the caller asks for them.

The library runs in the process of the consumer and calls the Hotdata API with the API key of the consumer. There is no hotmemory server. The first consumer is an incident investigator built on Hotdata. The library is not specific to it. A plain Python agent, a LangGraph agent, or any process with a Hotdata API key can use it.

Install

hotmemory needs Python 3.11 or later. The core package has no dependencies:

pip install hotmemory

Each driver and embedder that calls a service is in an extra. The hotdata extra adds HotdataStore. The openai extra adds OpenAIEmbedder.

pip install "hotmemory[hotdata,openai]"

Try the storage contract

MemoryStore needs an embedder for a search with query text. An embedder is a callable that turns a list of texts into a list of vectors. This example uses a toy embedder that counts two words:

from hotmemory import Filter, MemoryStore


def embed(texts):
    return [[text.count("disk") + 0.1, text.count("cpu") + 0.1] for text in texts]


store = MemoryStore(embedder=embed)
store.put(("team", "alerts"), "disk", kind="fact", content="The disk fills at night.")
store.put(("team", "alerts"), "disk", kind="fact", content="The disk fills at noon.")
store.put(("team", "alerts"), "cpu", kind="fact", content="The cpu spikes after a deploy.")

print(store.get(("team", "alerts"), "disk").id)  # team/alerts/disk@2
print([r.revision for r in store.history(("team", "alerts"), "disk")])  # [1, 2]
hits = store.search("disk", [("team",)], Filter(kind="fact"), k=1)
print(hits[0].record.content)  # The disk fills at noon.

Try the memory contract

Memory gives an agent the memory operations over any store. remember derives each key from the subject and the content, so a retried call writes nothing new. recall returns the records and one block of text, with one line for each record:

from hotmemory import Fact, Memory, MemoryStore


def embed(texts):
    return [[text.count("disk") + 0.1, text.count("cpu") + 0.1] for text in texts]


memory = Memory(MemoryStore(embedder=embed))
scope = ("team", "alerts")
memory.remember(
    [Fact(kind="fact", subject="disk", content="The disk fills at night.", sources=("chat-1",))],
    scope,
)
records, block = memory.recall("disk", [scope])
print(block)  # - The disk fills at night. [sources: chat-1] [valid: unknown to now]

load takes a document name, the Markdown text, a scope, and an extractor. The extractor gets each chunk, with the first heading and the heading path of the chunk at its top:

from hotmemory import Fact, Memory, MemoryStore


def embed(texts):
    return [[text.count("disk") + 0.1, text.count("cpu") + 0.1] for text in texts]


def last_line(text, observed_at, current):
    return [Fact(kind="fact", subject="disk", content=text.splitlines()[-1])]


memory = Memory(MemoryStore(embedder=embed))
text = "# Disk incident\n\n## Root cause\n\nThe disk fills at night.\n"
episodes, facts = memory.load("disk-incident", text, ("team", "alerts"), last_line)
print(episodes)  # ['team/alerts/disk-incident-0001@1']
episode = memory.store.get(("team", "alerts"), "disk-incident-0001")
print(episode.content.splitlines()[0])  # # Disk incident

Use the skill

skills/hotmemory/SKILL.md gives an agent the same operations as commands. The skill is a folder with the skill file and one script for each operation. The package does not include it, so you copy it from the repository.

  1. Install hotmemory in the Python that the agent runs. The extras are necessary only for a Hotdata database:

    pip install "hotmemory[hotdata,openai]"
    
  2. Copy the skill folder into the folder where your coding agent reads skills. Many agents use ~/.<agent>/skills/ for every project, or .<agent>/skills/ in one project. The documentation of your agent gives the correct folder.

    git clone --depth 1 https://github.com/hotdata-dev/hotmemory
    cp -r hotmemory/skills/hotmemory <skills-folder-of-your-agent>/
    

The agent runs the scripts from the skill folder. With --memory-file, they need no network and no key. With --database, they read the Hotdata and OpenAI keys from the environment.

Store memory in Hotdata

HotdataStore needs the hotdata extra, and an embedder for every write and search. The openai extra ships OpenAIEmbedder, which reads OPENAI_API_KEY. Any callable that turns a list of texts into a list of vectors also works. provision opens the database with the name, or creates it. It reads the connection from HOTDATA_API_KEY, HOTDATA_WORKSPACE, and HOTDATA_API_URL:

from hotmemory.hotdata import HotdataStore
from hotmemory.openai import OpenAIEmbedder

embedder = OpenAIEmbedder()
store = HotdataStore.provision(
    "agent-memory", embedder=embedder, model=embedder.model, dimensions=1536
)
store.put(("team", "alerts"), "disk", kind="fact", content="The disk fills at night.")
print([hit.record.id for hit in store.search("disk", [("team",)])])

One process writes to a database. docs/contracts.md gives the tables, the retrieval query, and the rules of the driver.

Benchmark

hotmemory ran LongMemEval-S, a public benchmark of 500 questions over long chat histories, on 2026-10-10. docs/benchmarks.md gives every number with its configuration.

On all 500 questions, on 2026-10-22, the memory arm scored 439 of 500 (87.8%). It ran capture with chunks of 1,000 characters and a gpt-4o-mini extractor, and recall with a budget of 16,000 characters, about 4,350 tokens of reader input. The reader and the judge were gpt-4o-2024-08-06. This is one run, and its 95% confidence interval is about 2.9 points on each side. The 392 questions that no tuning used scored 88.0%.

Retrieval needs no model except the embedder. The runner stored each session of a question as an episode in HotdataStore and searched with the question. The 419 scored questions had these results with the vector ranking. For 98.3% of them, an evidence session was in the top 5. For 99.3% of them, every evidence session was in the top 10.

Before that run, the end-to-end score ran on two samples of 54 questions, sample A on 2026-10-10 and sample B on 2026-10-14. Later rows give their own date. The reader and the judge were gpt-4o-2024-08-06.

What the reader got Sample A Sample B
Every session of the question, about 114,000 tokens 39 of 54 (72.2%) 43 of 54 (79.6%)
The 10 sessions that the search ranked first 45 of 54 (83.3%) 48 of 54 (88.9%)
The block of recall, after capture with a gpt-4o-mini extractor and the baseline prompt 19 of 54 (35.2%) 27 of 54 (50.0%)
The same, on 2026-10-14, with the detail prompt and a session source on each fact 31 of 54 (57.4%) 32 of 54 (59.3%)
The same, on 2026-10-15, with each session stored as an episode, and recall with episodes="search" and a budget of 64,000 characters, about 12,800 tokens 45 of 54 (83.3%) 45 of 54 (83.3%)
The same, on 2026-10-18, with each session stored as chunks of 1,000 characters (capture with chunk_chars=1000), and recall with episodes="search" and a budget of 16,000 characters, about 4,300 tokens 48 of 54 (88.9%) 46 of 54 (85.2%)

Facts alone score below the full history. With the baseline prompt, the extractor did not store the answer in 19 of the 35 misses on sample A, and in 16 of the 27 misses on sample B. With the detail prompt, these counts are 16 of 23 and 14 of 22. With the whole sessions that a search adds after the facts, the extractor did not store the answer in 5 misses on each sample. With chunks of 1,000 characters, this count is 2 on each sample. The chunk row scores above the full history on both samples. It scores 3 more than the 10 sessions on sample A and 2 less on sample B, with about one seventh of their tokens. With 54 questions, each score can be about 10 points off. With the baseline prompt, the memory arm differed by 14.8 points between the two samples. In the cloud, a search took 361 ms at p50 with the vector ranking, and 998 ms with the fused ranking.

Documents

Metadata

Release files for hotmemory 0.1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for hotmemory 0.1.0
File Size Uploaded Provenance
hotmemory-0.1.0.tar.gz 37.7 kB With provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for hotmemory 0.1.0
File Interpreter ABI Platform
hotmemory-0.1.0-py3-none-any.whl Python 3 none any Details

Total release size: 79.8 kB

Release files / hotmemory-0.1.0.tar.gz

Download URL hotmemory-0.1.0.tar.gz
Size 37.7 kB
Tags Source
SHA-256 checksum
How to use checksums
248edaa9a0606fdf755e92be3e6c9e4d049631b1e846f693837fa3d5c62b22a6
BLAKE2b-256 checksum
How to use checksums
2eeaaea46491551734a44f28de566fb43a871fe23ded6e74c9a5b9bc8fdec103
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 23, 2026.

Transparency log

Release files / hotmemory-0.1.0-py3-none-any.whl

Download URL hotmemory-0.1.0-py3-none-any.whl
Size 42.1 kB
Tags Python 3
SHA-256 checksum
How to use checksums
ff6fabbe0f57a9d1df8fbdf69651d06014106cb4d1d2b8c26d2927c8a80c1a07
BLAKE2b-256 checksum
How to use checksums
849332d8590aed7f1175a380fe1c955c29d869845e728c7733ec8824f39b0c1f
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 23, 2026.

Transparency log

Security for hotmemory 0.1.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

Full provenance

All 2 files in this release have been uploaded with provenance metadata.

Select from 2 files

Attestation for hotmemory-0.1.0.tar.gz

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 23, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Release history Release notifications | RSS feed

This release

0.1.0 This release

2 release files Full provenance

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page