agentleFS
eric-cieloeric-cielo/moflo/.claude/skills/memory-optimization/SKILL.md

memory-optimization

Skill19 starsChanged 3 months agoMITView on GitHub

Tune moflo's memory stack for speed, RAM, and index quality. Covers HNSW parameters (M, efConstruction, ef), vector quantization, batch operations, and common bottlenecks. Use when scaling past ~100k entries or when search latency regresses.

The file

We split this skill into the rules it gives an agent

2 rules. About 0 are common, 0 are distinctive, and 2 are very specific to this project.

  • ≈0

    Common · estimate

    Many files like this have a rule of this kind.

  • ≈0

    Distinctive · estimate

    This author's own choices. Worth a look.

  • 2

    Very specific

    Tied to their project's names, files or tools. Probably skip.

  • Common
  • Distinctive
  • Very specific
  1. Very specific:

    When the default moflo memory settings stop being enough — past ~100k entries, or when p95 search latency climbs — these are the levers.

    line 8
  2. Very specific:

    Don't rebuild the index on every test: Use a module-level singleton + beforeAll.

    line 112

≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
SKILL.md

MoFlo Memory Optimization

When the default moflo memory settings stop being enough — past ~100k entries, or when p95 search latency climbs — these are the levers.

HNSW Parameters

HNSW has three knobs. They trade build time, query time, memory, and recall.

import { HNSWIndex } from 'moflo/dist/src/cli/memory/index.js';

const index = new HNSWIndex({
  dimensions: 1536,        // must match your embedding model
  maxElements: 1_000_000,  // pre-allocated capacity
  M: 16,                   // graph connectivity (default 16)
  efConstruction: 200,     // build-time search width (default 200)
  metric: 'cosine',        // 'cosine' | 'l2' | 'ip'
});
KnobHigherLowerWhen to change
Mbetter recall, more RAM (~2×M pointers per point)less RAM, worse recallBump to 32–64 if recall@10 < 0.95; drop to 8 if memory-bound
efConstructionbetter index quality, slower buildfaster build, worse queries200–400 is sweet spot; only lower in test fixtures
ef (search-time, passed to search())better recall, slower queriesfaster queries, worse recallStart at 2×k, raise until recall plateaus

Rule of thumb: M and efConstruction are set once. ef is the runtime dial.

Quantization

moflo memory supports scalar quantization (Float32 → Int8) for a ~4× memory reduction with a ~1-2% recall hit. Turn it on when the index doesn't fit comfortably in RAM.

const index = new HNSWIndex({
  dimensions: 1536,
  maxElements: 5_000_000,
  quantization: {
    enabled: true,
    type: 'scalar',   // scalar (Int8) is the supported path
    rebuildThreshold: 10_000,
  },
});

Measure recall before/after on your own query distribution — public benchmarks don't predict your domain.

Batch Operations

Single-entry writes pay the HNSW insert cost per call. For bulk ingest, batch:

const entries: Array<[string, Float32Array]> = buildCorpus();

// Parallelise at the adapter level; don't await sequentially.
await Promise.all(
  entries.map(([id, vec]) => index.addPoint(id, vec))
);

// Or via MCP for moflo-native batch into .swarm/memory.db:
await mcp.memory_store(/* … */);  // upsert: true + Promise.all is fine

For >10k entries, prefer bin/build-embeddings.mjs / bin/index-all.mjs — they stream in batches with a progress bar and skip unchanged chunks via a hash file.

Caching

MofloDbAdapter has a built-in LRU cache (default 10k entries, 5-min TTL):

import { MofloDbAdapter } from 'moflo/dist/src/cli/memory/index.js';

const store = new MofloDbAdapter({
  cacheEnabled: true,
  cacheSize: 50_000,      // scale with working set, not total corpus
  cacheTtl: 10 * 60_000,  // 10 minutes
});

Cache hits on exact keys bypass HNSW entirely. If your workload is read-heavy and hits a narrow keyspace, this is the cheapest win.

Measuring

npx vitest bench src/cli/memory/benchmarks/vector-search.bench.ts

The bench prints linear vs HNSW times for 1k and 10k vectors. Run it before and after any parameter change — "it felt faster" is not a benchmark.

For production memory stats:

const stats = await mcp.memory_stats({});
// { entryCount, indexSize, cacheHitRate, avgSearchMs, … }

Common Bottlenecks

SymptomLikely causeFix
Cold-start of 5s on first searchHNSW loading from diskShare a single instance via beforeAll in tests; keep the adapter resident in long-running processes
Search latency climbs linearly with limitOver-fetching and re-ranking on the hot pathLower limit; raise threshold to prune
Inserts slow past ~100k entriesmaxElements too close to entry count → reallocationSet maxElements to 2× expected corpus
High RSS on a small corpusVector dimension mismatch with indexConfirm dimensions matches embedder output (OpenAI = 1536, local models vary)

Anti-Patterns

  • Don't rebuild the index on every test. Use a module-level singleton + beforeAll. HNSW cold-boot is ~5s.
  • Don't raise ef globally. Raise it on the specific queries that need recall. Default is fine for 90% of calls.
  • Don't quantize a small corpus. Below ~500k vectors the RAM saving doesn't justify the recall cost.
  • Don't measure in dev mode. The memory stack behaves differently under NODE_ENV=production; benches should match the target.

See Also

  • memory-patterns skill — API usage and namespace design
  • vector-search skill — RAG-specific patterns on top of the optimized index
  • src/cli/memory/benchmarks/ — runnable benches for every knob above

Download now (ZIP)

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

No reviews yet

People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.

  • It worked
  • Partly
  • It didn't
What did you use it for? e.g. Reviewing pull requests in a Rails app

Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.