Generated banner for WARM
Generated logo for WARM

WARM

Memory serverOfficial Writerslogic project

Created by Writerslogic

Published in writerslogic/warm. Publisher page

27 GitHub stars

What it is

WritersLogic Adaptive Retention & Memory (WARM): local document search (BM25 + embedding cosine) and vector-symbolic associative memory.
— the description by Writerslogic

AutoGineer overview, from the brain’s own files

WARM (WritersLogic Adaptive Retention & Memory) is a local-first memory engine designed to provide AI agents and applications with persistent storage and retrieval. It combines traditional document search—using stemmed BM25 and vector-based cosine similarity—with a vector-symbolic layer for associative memory and multi-hop queries. The system is built in Rust and can be deployed as an embedded library, an HTTP server, or an MCP server, allowing it to integrate with various agent hosts and development environments. It emphasizes local control, offering optional encryption and provenance features while avoiding external service calls or telemetry.

How it works

Memory model: Hybrid

AutoGineer overview, from the brain’s own files

The system stores text, vectors, and facts in a local directory. It uses a hybrid approach where document search combines chunking and BM25 with vector embeddings. The vector-symbolic layer utilizes sparse hypervectors to support associative memory, triples, and multi-hop queries. It provides an API for memory management including remember, recall, and forget operations, with support for source provenance and atomic storage updates.

Folders
FolderRoleFiles
.githubagent-config37
assetsattachments10
docsdocs1850
examplesexamples47
scriptsscripts77
srcsource-code327
teststests362
benchesfolder7
benchmarksfolder2898
bindingsfolder273
deployfolder18
figuresfolder6
fuzzfolder54
integrationsfolder225
interopfolder3
notebooksfolder3
npmfolder1
proptest-regressionsfolder1
schemasfolder9

The agent reads

Requirements

Runtimes: Node.js, Python >=3.9, Rust

Databases: SQLite

API keys (by name): WARM_API_KEY

Works with: Gemini CLI

Set it up

  1. This brain runs code automatically: 1 hook (claude-code), 1 script. Review benchmarks/results/sbg_positions_development/setup.sh, integrations/editors/claude-code/plugin/hooks/hooks.json before opening the folder in Claude Code. No step below turns a hook on for you.

    • benchmarks/results/sbg_positions_development/setup.sh: sh benchmarks/results/sbg_positions_development/setup.sh
    • integrations/editors/claude-code/plugin/hooks/hooks.json: node
  2. Not scanned by AutoGineerThe author’s README also describes installing it from a clone of its repository. Read its install section: AutoGineer did not scan that path. https://github.com/writerslogic/warm/blob/e176d5572dd86bf2233bcb120e3a485dc109ea3a/README.md#get-started
  3. Not scanned by AutoGineerThe author’s README also describes installing it as the npm package writerslogic-warm. Read its install section: AutoGineer did not scan that path. https://github.com/writerslogic/warm/blob/e176d5572dd86bf2233bcb120e3a485dc109ea3a/README.md#get-started
  4. Created by Writerslogic. Published in writerslogic/warm. Licence: Apache License 2.0.

Usage

AutoGineer overview, from the brain’s own files

  • Integrating memory into an AI agent via the MCP server.
  • Building local-first applications that require embedded search and storage.
  • Providing a multi-tenant memory service via the HTTP server.
  • Using the Rust library for in-process memory management.
“Remember that the project deadline is Friday.”
The agent stores the fact with associated metadata, making it available for future retrieval.
“Recall information about the project deadline.”
The agent retrieves the stored fact using hybrid search and provides the information with source provenance.

Documentation by Writerslogic

<img src="https://raw.githubusercontent.com/writerslogic/warm/main/assets/crystal-halo/crystal-detailed-static.png" alt="WARM logo" width="96" align="left">

WARM

Local memory for AI agents and applications.

WARM (WritersLogic Adaptive Retention & Memory) gives agents persistent memory, full-text and vector search, and source provenance in one embeddable Rust engine. Use it inside your application, through HTTP, or from an MCP client, with storage on infrastructure you control.

Image: CI Image: MSRV 1.89 Image: OpenSSF Scorecard Image: OpenSSF Best Practices Image: License: Apache-2.0 Image: WARM MCP server: quality and maintenance score on Glama

Website · Docs · Get started · Standards and provenance · Evaluation · Capabilities · Limits · Contribute

<br clear="left">

What it is

WARM is a Rust library that stores text, vectors and facts in a directory on your machine and finds them again. It ships with optional Node.js, C, WASM and UniFFI bindings, an HTTP server with portable JavaScript and Python clients, and an MCP server. The embedded engine makes no service calls or telemetry requests. HTTP clients connect to the server you configure; model stages are opt-in.

CapabilityWhat you get
Document searchChunking, stemmed BM25 over blocked postings, Boolean and phrase queries, hybrid fusion with embeddings you supply, metadata filters, byte offsets
Vector indexGraph index with a memory-mapped vertex file, an updatable delta for inserts and deletes, optional query-aware routing trained on sample queries
Memory APIremember, recall, forget and explain with time validity and supersession; conversation memory with source provenance
StorageAtomic replace and delete, crash-safe journal and checkpoints, verified compaction, one writer per store
SecurityOptional AES-256-GCM storage encryption with documented coverage and limits, signed audit log, COSE/SCITT provenance
Vector-symbolic layerSparse hypervectors with bind, bundle and permute, triples with multi-hop queries, Hopfield cleanup

Who it's for

You are buildingWhat you get
An agent or assistant that needs memoryA memory API with forgetting that removes facts from the store, and an MCP server for editors and agent hosts
A local-first or offline appEmbedded search and storage in one directory, with no server process and optional encryption
A service that needs vector or text searchwarm-server over HTTP with tenants and scoped keys, or the library in-process

Get started

For an editor or agent host, start with the MCP integration. For an application, choose the Rust library or HTTP server below. WARM runs locally or on your own infrastructure; this repository does not provide a managed cloud service.

To try the offline memory demo from source:

git clone https://github.com/writerslogic/warm
cd warm
cargo run --release --example demo-offline-agent

<details open> <summary><strong>Rust</strong></summary>

From your own Rust project, add the current Apache-2.0 source. The crate is warm-rust; the library is imported as writerslogic_warm. The MSRV is Rust 1.89; local-models and --all-features need Rust 1.94 or newer.

cargo add warm-rust

The historical v0.6.1 source remains AGPL-3.0-or-later; it is available from that Git tag, not as a warm-rust 0.6.1 release on crates.io.

use writerslogic_warm::{DocumentInput, WarmCore, SearchOptions};

let dir = tempfile::tempdir()?;
let warm = WarmCore::new(4096, Some(dir.path().display().to_string()), None)?;
warm.memorize_document(DocumentInput {
    id: "backups".into(),
    text: "Restore deleted documents from verified backups.".into(),
    source_uri: Some("operations.md".into()),
    version: Some("1".into()),
    metadata: Some(serde_json::json!({ "project": "alpha" })),
    chunk_words: None, overlap_words: None, store_text: None, embeddings: None, title_weight: None,
})?;
let hits = warm.search_documents("restore backups", &SearchOptions::default())?;
println!("{} {:?}", hits[0].document_id, hits[0].source_uri);

Rust API change in 0.6.6 (0.6.5 returns these values directly): WarmCore::query, query_batch, and analyze_components return Result. Handle the result with ? or an explicit error branch; deferred-encoding failures no longer become successful partial query results. get_document, list_documents, get_document_info, and list_document_info also return Result; retained-text and checkpoint decoding failures propagate instead of panicking, and reads no longer hydrate the entire checkpoint or hold store locks during text I/O.

</details>

<details> <summary><strong>JavaScript and TypeScript: portable client</strong></summary>

warm-sdk 0.2.1 is the portable HTTP client for a separately running warm-server. It has no native binaries or runtime dependencies and uses standard Fetch and Web Streams APIs (Node 18 or newer). Installing or importing it does not load the embedded engine or download models. For a published release, install the client in your application:

npm install [email protected]

Check the available npm versions. To build the client from this checkout:

npm ci --prefix bindings/js/warm-sdk
npm run build --prefix bindings/js/warm-sdk

In your application, install that directory with npm install /absolute/path/to/warm/bindings/js/warm-sdk.

Start the server in a separate terminal:

cargo build --release --features server --bin warm-server
WARM_API_KEY=change-me target/release/warm-server --input-dim 384
import { WarmClient } from 'warm-sdk'

const warm = new WarmClient({
  url: process.env.WARM_URL ?? 'http://127.0.0.1:8080',
  apiKey: process.env.WARM_API_KEY, tenantId: 'demo',
})
await warm.memory.remember('Restore deleted documents from verified backups.', {
  id: 'backups', metadata: { project: 'alpha' },
})
const hits = await warm.memory.recall('restore backups', { filter: { project: 'alpha' } })
console.log(hits[0]?.text)

Set WARM_API_KEY to the server's key before running the client. This memory example uses lexical retrieval and needs no embedding model. A runnable source example also checks retrieval and deletion in an isolated namespace:

WARM_URL=http://127.0.0.1:8080 WARM_API_KEY=change-me \
  node examples/quickstart/js-client/quickstart.mjs

See the client API and release availability. Browser deployments must permit the application's origin at the HTTP service boundary.

</details>

<details> <summary><strong>Node.js: optional embedded engine</strong></summary>

writerslogic-warm embeds the Rust engine in Node. For a published engine release, install it explicitly with npm's optional dependencies enabled:

npm install [email protected]

Check the available npm versions. To build from the cloned repository, with Rust installed:

npm ci --omit=optional
npm run build

The portable client and embedded engine are separate packages with different APIs. listDocuments supports scoped pruning. See the integration guide for source provenance, namespace isolation, dry runs and deletion limits.

const { WarmMemorySystem } = require('writerslogic-warm')
const { DocumentMemory } = require('writerslogic-warm/semantic')

async function main() {
  const dir = require('node:fs').mkdtempSync(require('node:path').join(require('node:os').tmpdir(), 'warm-readme-'))
  const memory = new DocumentMemory(new WarmMemorySystem(4096, dir))
  await memory.memorize({
    id: 'backups', text: 'Restore deleted documents from verified backups.',
    sourceUri: 'operations.md', version: '1', metadata: { project: 'alpha' },
  })
  const [hit] = await memory.search('restore backups', { filter: { project: 'alpha' } })
  console.log(hit.documentId, hit.sourceUri, hit.text)
  await memory.flush()
}
main().catch(error => { console.error(error); process.exit(1) })

</details>

<details> <summary><strong>Server and Python</strong></summary>

The Python package warm-sdk is an HTTP client for warm-server, which stores vectors you supply. (warm-python, imported as writerslogic_warm, provides native vector indexes and phase vectors, but no document search.)

cargo build --release --features server --bin warm-server
WARM_API_KEY=change-me target/release/warm-server --input-dim 384 &
uv pip install warm-sdk
from writerslogic_warm_sdk import WarmClient

client = WarmClient(url="http://127.0.0.1:8080", api_key="change-me", tenant_id="demo")
client.add_documents([{"id": "a", "vector": [0.1] * 384, "text": "hello", "metadata": {}}])
print(client.query([0.1] * 384, top_k=1)["matches"][0]["id"])

Endpoints, flags, tenants and limits are in the server docs. A runnable Python quickstart with a toy embedder is in examples/quickstart/python.

</details>

<details> <summary><strong>MCP</strong></summary>

warm-mcp serves a store to any Model Context Protocol client over stdio or HTTP:

npx -y writerslogic-warm-mcp                                # stdio; downloads a verified binary on first run
npx -y writerslogic-warm-mcp --transport http               # http://127.0.0.1:8765/mcp

The MCP package is a separate launcher. To build the server from source:

cargo build --release --features mcp,security --bin warm-mcp   # add local-models for semantic recall
./target/release/warm-mcp                                       # stdio
./target/release/warm-mcp --transport http                      # http://127.0.0.1:8765/mcp

Client setup, data directory and the one-writer rule: MCP integration.

For normalized content from multiple applications, see the organizational knowledge adapter.

</details>

The five-minute quickstart walks through ingest, search, a SQLite FTS5 comparison and encryption in Rust, Python and Node, and CI runs that code on every pull request. For a whole agent memory with no embeddings and no network, run cargo run --example demo-offline-agent.

<a id="headline-results"></a> <a id="where-its-behind"></a>

Evaluation

Recorded results and limitations cover memory quality, text retrieval and vector search. Each result retains its workload, hardware, model, source revision and known losses. The full comparison and reproduction protocol provide the evidence for evaluating WARM on your own workload.

What ships today

CapabilityStatusDocumented limit
Hybrid document search (BM25 + exact cosine, filters, byte offsets)ShipsExact scan of eligible chunks; benchmark your corpus before assuming capacity (guide)
Boolean lexical search (+required, -excluded, quoted phrases)ShipsFlat queries only, no nesting; an empty or only-excluded query matches nothing (design)
Atomic replace/delete, crash-safe journal, verified compaction, process lockShipsOne writer per store; compaction is not secure erasure
Vector index (qgraph vertex graph, memory-mapped)ShipsBuild time and serving RSS behind hnswlib on SIFT-1M (gaps)
Updatable vector index (durable delta for inserts and deletes)ShipsSingle writer; format in VECTOR-UPDATES.md
Query-aware graph routing (trained on sample queries)Ships (opt-in)Needs representative training queries; tested on VIBE llama and yi (report)
Memory API: remember, recall, forget, explainShipsForgetting removes a fact from the store; it does not cover what a model inferred (docs)
Conversation memory (conversation-memory)ShipsBounded context with exact source provenance; native recall not yet benchmarked on LongMemEval end to end
Meaning memory: triples, multi-hop, Hopfield cleanupShips (runtime opt-in)Tested on synthetic and 2,120-fact sets (research_bench_16384_256.json)
Union-bundle membership (experimental)ResearchAt D = 16,384: positive gap to N = 500 (4% false positives), tested to 2,500 (benchmark_scaling_results.json)
Sparse vector index (memorize_vector)ExperimentalNot competitive with HNSW (results)
Encrypted stores (security)ShipsAES-256-GCM, Argon2id; covers the log, index caches and the text segment. Metadata, file names and sizes are not encrypted
Signed audit log, credential-gated access, COSE/SCITT/C2PA (provenance)ShipsHost must authenticate DIDs; PoSME, RATS, did:web not implemented
On-device models (local-models: Qwen3 embed/rerank/LLM)ShipsLocal weights only; never downloads
warm-server HTTP API, multi-tenant (server)ShipsSingle node; TLS, per-tenant scoped keys (guide)
MCP server (mcp: warm-mcp, stdio and HTTP)ShipsEncryption needs security; semantic recall needs local-models
JavaScript/TypeScript client (warm-sdk 0.2.1)Source and release buildsPortable HTTP client; requires a separately running server
Embedded Node.js (writerslogic-warm 0.6.8)Source and release buildsEight optional native platform packages; separate from the client
C, Go, .NET, Java, Kotlin, Swift and WebAssembly bindingsSource availableRequire local builds; the language packages and native bundles are not yet published (runtime guides)
PythonHTTP client (warm-sdk); native vector indexes and phase vectors (warm-python)No in-process document search
Query-private search (private-search)ExperimentalFor searching an index someone else holds; hides the query vector from the scorer only (notes)

Optional engine capabilities use Cargo features or runtime configuration; Cargo features lists the build choices.

The compatibility policy defines API stability, deprecation windows and storage-format migration rules.

Architecture

flowchart TB
  subgraph bindings["Bindings and servers"]
    rust["Rust crate"]
    node["Node: writerslogic-warm (napi)"]
    ffi["C, WASM, UniFFI"]
    clients["JavaScript and Python: warm-sdk"]
    server["warm-server (HTTP)"]
    mcp["warm-mcp (stdio, HTTP)"]
  end
  subgraph engine["Engine API"]
    core["WarmCore: documents, vectors, facts, mutation gate"]
    prov["Security and provenance: signed audit log, COSE/SCITT"]
  end
  subgraph indexes["Indexes and memory"]
    text["Text index: blocked postings, BM25, Boolean and phrase"]
    vector["Vector index (qgraph): vertex file, updatable delta, query-aware projection"]
    memory["Memory API: remember, recall, forget, conversation memory"]
    vsa["Vector-symbolic layer: bind, bundle, Hopfield cleanup"]
  end
  subgraph storage["Storage"]
    journal["Journal and checkpoints"]
    segments["Append-only segments (CRC32, LZ4)"]
    mapped["Memory-mapped files"]
    crypto["AES-256-GCM encryption (optional)"]
  end
  clients --> server
  rust --> core
  node --> core
  ffi --> core
  server --> core
  mcp --> core
  core --> text
  core --> vector
  core --> memory
  core --> vsa
  core --> prov
  memory --> text
  text --> journal
  vector --> journal
  memory --> journal
  journal --> segments
  segments --> mapped
  segments --> crypto

Module map: docs/ARCHITECTURE.md.

Limits

  • Not anonymous. Hypervector sketches and term counts are not encryption; anyone with a store can encode candidate text and compare. storeText: false keeps term counts, IDs and embeddings, so it is not a privacy control.

  • Document search is conventional. It does not use the hypervectors; the holographic parts are the algebra and the meaning memory.

  • One writer per store. A second writing process fails at open with a lock error.

  • Capacity numbers are points, not guarantees, and are stated only over the tested range (capacity).

  • Benchmark results are single machines. Conditions are in each results file; the single-core ann-benchmarks run and the VIBE high-recall points are losses (see Where it's behind).

  • Masking is obfuscation. Client-side vector masking preserves every pairwise similarity.

  • A store is a directory and WarmCore::new(.., None, ..) uses the current directory.

Full statement: docs/PRIVACY.md. Report vulnerabilities privately via SECURITY.md.

Contributing

CONTRIBUTING.md: setup, the checks CI runs, DCO sign-off (git commit -s, no CLA). Start with a good first issue or Discussions. See the Code of Conduct. Benchmark changes regenerate the results file they touch; the README cites files, not remembered figures.

License

Apache-2.0. See LICENSE. Use, modify and embed it in open-source or proprietary software, including network services, with no copyleft obligation. The historical v0.6.1 source remains available under its AGPL-3.0-or-later license.

docs/SECURITY.md

Security Model

Threat Model

Assets Protected
  1. Stored vectors: Hyperdimensional representations of user content stored in arena segments and index files.

  2. Operation history: Which IDs were memorized, deleted, or compacted, and when.

  3. Signing keys: Ed25519 private keys used for audit log non-repudiation.

  4. Encryption keys: AES-256-GCM derived keys for data-at-rest protection.

Threat Categories
ThreatMitigationFeature Flag
Unauthorized read of stored dataAES-256-GCM encryption at restsecurity
Tampering with arena logCRC32 for accidental corruption; AES-GCM authentication when encrypteddefault / security
Repudiation of operationsSigned append-only audit trailsecurity
Key extraction from diskEd25519 private key stored as raw 32 bytes; protect via OS file permissionssecurity
Inference of original content from vectorsNo inherent protection; see PRIVACY.mdNone
Side-channel on signinged25519-dalek uses constant-time operationssecurity
Trust Boundaries
  • System boundary: Vector APIs retain representations; document APIs retain source passages by default, plus terms, metadata, source identifiers, and optional dense embeddings. Lossy encoding does not prevent inference.

  • Storage boundary: Arena payloads and index files can be encrypted. Schema metadata, filesystem structure, audit/provenance sidecars, and signing keys have separate policies; encryption does not conceal every file or access pattern.

  • Document text cache: With store encryption enabled, version 2 documents.text records use AES-256-GCM with their segment offsets as authenticated data. Equal passages receive independent nonces; altered or relocated records fail authentication. Legacy plaintext caches are rebuilt from the arena at open. Schema metadata, filesystem structure, audit/provenance sidecars and signing keys retain the separate policies described above.

  • N-API boundary: Node.js callers interact via typed N-API bindings. Input validation occurs at the Rust boundary (ID length checks, dimension bounds, passphrase presence).

Cryptographic Choices

Ed25519 Signing
  • Library: ed25519-dalek v3 (pure Rust, constant-time)

  • Key generation: rand::rng() (OS CSPRNG via getrandom)

  • Key storage: Raw 32-byte secret key at {storage_path}/hms_signing.key

  • What is signed: Legacy entries cover [timestamp_ms: u64][op: u8][id_hash: 32] (41 bytes). Schema-6 effects prepend WARM-AUDIT-2\0 and their 16-byte delivery identity (70 bytes total); use AuditEntry::signable_bytes().

  • Verification: Public key derived from stored secret key on load

AES-256-GCM Encryption
  • Library: aes-gcm v0.11 (AES-NI hardware acceleration where available)

  • Key derivation: Argon2id (default parameters) from user passphrase + 16-byte random salt

  • Salt storage: {storage_path}/encryption.salt (generated once, persisted)

  • Nonce: 12-byte random per encryption operation (prepended to ciphertext)

  • Scope: Encrypts serialized log entries before LZ4 compression in arena, and index files (NSG, IVF) on disk

ID Hashing
  • With security feature: SHA-256 (32-byte output)

  • Without: FxHash (8-byte, zero-padded to 32)

  • Purpose: Audit log stores hashes of vector IDs, never raw IDs

Limitations

  1. No automatic audit-key rotation: Historical audit signatures remain valid under their original public keys. Preserve those independently trusted keys when selecting a new signing key; the audit records do not carry a signer identifier or a rotation trust chain. Re-signing old events would change their original evidence and is not required to verify them.

  2. Library access control: The embedded library has no user/role model; its caller controls access. The separate HTTP server supports scoped keys and tenant isolation.

  3. Passphrase in config: The encryption passphrase is passed via SecurityConfig. The calling application is responsible for secure passphrase management (environment variables, secret managers).

  4. CRC32 is not cryptographic: Without the security feature, arena integrity relies on CRC32, which detects accidental corruption but not adversarial tampering.

  5. No forward secrecy or externally anchored history: A compromised signing key can forge entries. Per-entry signatures do not detect deletion, truncation, or reordering of otherwise valid records without an independently retained history.

  6. Salt reuse across sessions: The Argon2 salt is generated once per storage path. This is acceptable for single-user local storage but not for multi-tenant deployments.

Optional model dependency review

local-models requires Candle 0.11.1 or later; the lockfile resolves ZIP 9.2.0. This replaces the ZIP 8.6 dependency affected by GHSA-m665-v7pm-7grj, GHSA-q7v9-x93c-xqv3, GHSA-8hxf-qr8p-62x4, GHSA-hjqx-j4rw-g7xv, and GHSA-9hj8-73fh-9963. The upstream fix is Candle PR 4078, included in the 0.11.1 release. The minimum version applies to CPU, Metal and CUDA dependency declarations.

WARM loads these models through VarBuilder::from_mmaped_safetensors in src/core/models/mod.rs; it does not invoke Candle's PyTorch ZIP reader or archive extraction. The prior reachability disposition did not declare ZIP 8.6 generally safe. Reassess the boundary before adding an archive loader, and retain model and binding regression checks when updating Candle.

JavaScript development dependencies

The integration test workspace's LlamaIndex fixture pulls deepmerge 4.3.1 through html-to-text. GHSA-gcqx-w48m-w2h4 has no patched deepmerge release as of October 31, 2026. It is a development dependency, not bundled into the WARM adapters; no production safety claim is made for consumers' independently installed LlamaIndex dependencies. Keep the alert open pending the upstream dependency change. The workspace's tsup 9 upgrade removes the vulnerable esbuild development-server dependency.

Optional Python integration dependencies

The SDK's all, embedchain, phidata, and legacy semantic-kernel extras and their three legacy adapter modules are retired. Embedchain forces an obsolete dependency stack; the old Semantic Kernel implementation also cannot satisfy its framework contract. Phidata's upstream is archived, and its WARM vector-store adapter also fails construction with six unimplemented abstract methods. Its retirement reflects support/correctness failures, not a newly discovered vulnerability. This retirement does not remove the separate writerslogic-warm-integrations package's current Semantic Kernel adapter, whose resolved dependencies still require independent review.

The SDK now requires Python 3.11 or newer. Python 3.10 reached end of life on October 1, 2026; retaining it also prevented patched Pillow and Filelock releases. pydantic-ai now installs the official slim distribution, without all provider SDKs. The refreshed lock uses Pillow 13.0.0, Filelock 4.2.6, and Pydantic AI Slim 2.64.0. The Filelock constraint is a repository resolver guard, not a dependency override or a guarantee for independently resolved consumer environments. It selects LiteLLM 1.103.10 because 1.106.6 requires Filelock below 4; the documented DSPy profile pins that compatible pair and passes its local retrieval/cache tests. An unconstrained latest installation does not reproduce this profile. Both WARM Python packages also publish the Filelock floor in their DSPy extras, so those extras cannot silently resolve a Filelock 3 release; incompatible application pins fail resolution instead.

The full SDK lock scan on October 31, 2026 still matches four distinct Chroma advisories and one DiskCache advisory (OSV also returns duplicate PYSEC aliases):

  • Chroma 1.5.9 remains in import-chroma, the importer test group, and CrewAI's transitive dependencies. Code injection, pre-authentication code injection, tenant authorization, and cross-tenant access advisories include that release. The importer requires at least 1.5.9 and explicitly selects the Rust backend for local reads, disables embedding-function construction, and validates returned collection scope before reading records. Regression tests cover poisoned configuration, backend overrides and the real HTTP client's response handling. The reviewed WARM-side paths do not invoke the vulnerable Python server/configuration code. This does not patch Chroma or certify an external server's authorization, CrewAI's built-in storage, or arbitrary use of the installed dependency. The scoped callgraph review is in benchmarks/results/release_0_6_7/release-alert-dispositions.json.

  • DSPy requires DiskCache 5.6.3, whose default pickle deserialization permits code execution if an attacker can write its cache directory (GHSA-w8v5-vhqr-4h9v). Shared or untrusted cache directories are unsafe. The verified DSPy profile disables disk caching before first use and tests a fresh process that rejects DiskCache imports. Both WARM-owned DSPy adapters also bypass caching on actual dspy.Embedder calls without changing global policy. Generic callables and separate application cache/LM use remain caller-controlled; DiskCache itself and untrusted serialized DSPy programs remain outside these protections.

These are dependency matches, not five reproduced WARM exploits. The base HTTP client depends only on httpx and sniffio; install only needed extras and audit the resolved deployment environment. A consumer's PyPI installation is not bound by the repository lock. Neither this SDK scan nor retirement establishes the security of the separate Python/JavaScript integration packages. No advisories are suppressed. The remediation record preserves the full before/after scan, resolver trials, and remaining gates.

The earlier note associated mem0ai 0.1.116 with GHSA-7587-9684-52r6. The current advisory range starts at 0.1.117, so that specific attribution was incorrect. Other legacy mem0 advisories were separate findings; retirement removes the old dependency fork rather than asserting it was safe.

Documentation generator dependency

TypeDoc 0.28.20 depends on minimatch 10, affected by GHSA-g3hv-75wg-m249. The advisory concerns attacker-controlled patterns at optimizationLevel >= 2; the inspected TypeDoc calls use default optimization. This is build tooling, not the WARM service. Minimatch 11.0.1 is patched but removes matchOne, which TypeDoc's glob traversal calls. A forced major override was rejected as incompatible. Keep the alert open and upgrade when TypeDoc supports the patched API; verify generated reference pages and glob traversal, not just installation.

Audit Trail

For schemas 2–5, {storage_path}/audit.bin is an append-only binary file with fixed-size 105-byte entries:

[timestamp_ms: u64][op: u8][id_hash: 32 bytes][signature: 64 bytes]
  • Operations: Memorize (1), Delete (2), Compact (3)

  • Timestamps: Milliseconds since Unix epoch

  • Queryable: audit_since(timestamp_ms) returns all entries at or after a given time

  • Tamper evidence: When signing is enabled, each entry carries an Ed25519 signature over its timestamp, operation, and ID hash

Audit reads reject complete records with unknown operation codes, including records outside the requested timestamp range, and report the corrupt record's byte offset. This is structural validation, not automatic signature verification. A trailing incomplete record is excluded from reads and durably truncated on open or before the next append under the audit writer lock. Complete records are retained, including records whose write completed but whose sync reported an error. Recovery preserves alignment; it does not reconstruct missing audit events or establish exactly-once delivery. A failed repair prevents the new audit append, but the associated core mutation may already be committed as described in the committed-effect contract.

Schema 6 preserves legacy history and writes new entries to audit.effects.bin with a version header, effect identity, and per-record checksum. Enabled vector memorize/delete and compaction operations journal their audit intents atomically with the business change. Open and flush_audit() recover queued delivery without reapplying that change. Delivery is ordered and deduplicated across the write/acknowledgement crash interval, with at most 1024 pending effects. A full backlog rejects additional audited changes before commit. Original signatures survive recovery unchanged; retain the original verification key. Neither CRC32 nor individual signatures prove that no whole record was removed. Historical history gaps, provenance delivery, and document/meaning audit coverage remain separate work. See the persisted layout and delivery invariants.

IDF Clipping Poisoning Defense (Meaning Memory)

Threat

When meaning memory is enabled, AtomMemory and CompositeMemory use IDF-weighted posting-list overlap scanning to rank candidates during structural queries and Hopfield attractor cleanup. An attacker who can insert vectors with carefully chosen active dimensions could exploit extreme IDF weights to dominate similarity scores, causing the system to return attacker-controlled atoms as query results.

For example, an adversary could insert atoms that activate rarely-used dimensions, inflating those dimensions' IDF weights. Subsequent queries touching those dimensions would disproportionately favor the poisoned atoms.

Mitigation: Proportional IDF Clipping

The IdfWeights module applies proportional clipping to bound all IDF weights at clip_factor * median(weights). This is computed as follows:

  1. Collect all positive IDF weights.

  2. Sort them and find the median.

  3. Cap any weight exceeding clip_factor * median to that threshold.

The default idf_clip_factor is 3.0, meaning no dimension's IDF weight can exceed 3x the median weight. This limits the maximum influence any single dimension can have on overlap scores, regardless of how many poisoned vectors are inserted.

Configuration

The clip factor is configurable via MeaningConfig:

config.meaning.idf_clip_factor = 3.0; // default: cap at 3x median

Lower values provide stronger poisoning resistance at the cost of reduced discrimination between rare and common dimensions. Evaluate the effect on your own retrieval and adversarial fixtures; no clipping value provides a general poisoning-resistance guarantee.

Limitations
  • IDF clipping is a statistical defense, not a cryptographic one. It bounds the impact of poisoned dimensions but does not prevent insertion of adversarial vectors.

  • Clipping is applied globally during recompute() and is not per-query. A large batch of poisoned inserts between recomputation cycles could temporarily skew results.

  • The defense assumes a well-populated memory. With fewer than ~10 atoms, the median is unstable and clipping may be ineffective.

Enabling Security Features

Rust
// In Cargo.toml
[dependencies]
warm-rust = { version = "0.6", features = ["security"] }
let mut config = WarmConfig::default();
config.security.signing_enabled = true;
config.security.encryption_enabled = true;
config.security.encryption_passphrase = Some("your-passphrase".to_string());
config.security.audit_enabled = true;

let warm = WarmCore::new(16384, Some("./storage".to_string()), Some(config))?;
Node.js (N-API)
const warm = new WarmMemorySystem(16384, './storage', {
  signingEnabled: true,
  encryptionEnabled: true,
  encryptionPassphraseEnv: 'WARM_PASSPHRASE',
  auditEnabled: true,
});

// Query audit trail
const entries = await warm.auditSince(Date.now() - 86400000); // last 24h

auditSince requires a nonnegative safe integer timestamp. Each result includes hexadecimal signature and signableBytes, plus effectId for schema-6 deliveries. The signed flag means a signature is present; it does not verify authenticity. Use Node's crypto.verify(null, Buffer.from(entry.signableBytes, 'hex'), trustedPublicKey, Buffer.from(entry.signature, 'hex')) with an independently trusted Ed25519 public key. Verification authenticates the signed bytes; decode those bytes or compare the displayed fields against them when processing an untrusted response. Legacy messages are 41 bytes; effect-aware messages are 70 bytes and include the delivery ID. Rust callers can name writerslogic_warm::AuditEntry and AuditOp and, with security, call AuditEntry::verify_signature(&trusted_key); unsigned entries are rejected. WarmCore::audit_verifying_key() and Node's auditVerifyingKey() expose the currently configured public key as 32 bytes and hexadecimal respectively, or None/null when signing is disabled. Establish trust independently before retaining this public key for historical verification; retired private keys are not required to verify old entries. Neither interface establishes completeness or ordering of the entire history.

Custom builds fail if requested encryption/signing support is unavailable. The standard npm build includes security; use securityStatus() to confirm active configuration. Audit/provenance sidecar failures can occur after the main arena mutation commits. See production-readiness.md for transaction and failure boundaries.

512 files · 481 not served here

Advantages

  • Supports local-first operation with no external service calls or telemetry. evidence: README.md
  • Provides a memory API that allows for explicit fact removal via a forget operation. evidence: README.md

Limitations

Security

Risk level: Medium risk

This brain runs

Install scripts (1)

  • benchmarks/results/sbg_positions_development/setup.sh: sh benchmarks/results/sbg_positions_development/setup.sh

MCP servers (3)

  • integrations/editors/claude-code/plugin/.mcp.json (writerslogic-warm): npx -y writerslogic-warm-mcp
  • integrations/editors/claude-desktop/claude_desktop_config.json (writerslogic-warm): npx -y writerslogic-warm-mcp
  • integrations/editors/gemini-cli/gemini-extension.json (writerslogic-warm): npx -y writerslogic-warm-mcp

Hooks (1)

  • integrations/editors/claude-code/plugin/hooks/hooks.json (SessionStart): node
  • Medium risk: runs-mcp-server-unpinned-runner (integrations/editors/claude-code/plugin/.mcp.json)
  • Medium risk: runs-mcp-server-unpinned-runner (integrations/editors/claude-desktop/claude_desktop_config.json)
  • Medium risk: runs-mcp-server-unpinned-runner (integrations/editors/gemini-cli/gemini-extension.json)
  • Low risk: scripts-present (benchmarks/results/sbg_positions_development/setup.sh)

Attribution and licence

Created by
Writerslogic
Declared authors
  • WritersLogic, Inc. (declared in package.json)
  • WritersLogic, Inc. (declared in pyproject.toml)
  • WritersLogic Contributors (declared in CITATION.cff)
Publisher
Writerslogic (Official Writerslogic project)
Source
writerslogic/warm · commit e176d55
Licence
Apache License 2.0 (files served here)
  • ATTRIBUTION.md (written by AutoGineer)
Synced

AutoGineer is not affiliated with or endorsed by Writerslogic.

Install from source

481 of its files are not served here, so there is no ZIP. writerslogic/warm at e176d55