A local vector-memory backend for JIGGA. Semantic neighbourhood search over your agents' memory, on your own machine — no API calls, no per-query cost, nothing leaving the box.
JIGGA's built-in memory search is SQLite FTS5: excellent when you know the words, useless when you don't. Ask it "go-to-market schedule for indie devs" and a note reading "Our go-to-market timing lands end of week for the indie dev crowd" does not come back, because the two share no matching term. This pack answers that query.
It is a capability pack, not a fork: JIGGA declares a memory.vector slot and
resolves it through an approved manifest, so this code — and its dependencies —
stay outside JIGGA's core, which is stdlib + PyYAML by design.
pip install -e . # into the same environment as jigga
python -m memory_vector_local.install # copies the manifest into ~/.jigga
jigga capabilities approve ~/.jigga/capabilities/memory-vector-local/manifest.yaml --approveThen select it in ~/.jigga/config.yaml:
memory:
backends:
keyword: file
vector: memory-vector-localjigga memory search <query> now fuses vector hits with keyword hits. Approval is
a separate, deliberate step: naming a pack in config is not enough to get its code
imported, and this package will not grant itself that permission.
| dependency | what it captures | |
|---|---|---|
hashing (default) |
none | overlap in wording — including reordered and partial overlap a keyword index scores poorly |
sentence-transformers |
~torch | meaning — "car" near "automobile" |
The default is stdlib feature hashing so the pack installs and runs anywhere, including in CI, without downloading model weights. It is not semantic. It finds documents phrased like your query, which is a real improvement over exact term matching and is not the same thing as understanding. For actual semantic search, install the extra:
pip install -e ".[semantic]"memory:
vector_local:
embedder: sentence-transformers
model: BAAI/bge-small-en-v1.5 # ~400MB, downloaded oncememory:
vector_local:
embedder: hashing # hashing | sentence-transformers
dimensions: 512 # hashing only
model: BAAI/bge-small-en-v1.5
min_similarity: 0.0 # see belowmin_similarity is worth tuning. Vector search always has an answer: it ranks
every document and returns the top k, so with three documents in memory the third
comes back however unrelated it is. Keyword search does not behave that way, and a
fused result list padded with noise is worse than a short one. The right floor is
embedder-specific — hashing similarities are signed and centre near zero, while a
sentence-transformers cosine rarely drops below ~0.2 — so it is a config value, not
a constant.
- Derived data. The store is
~/.jigga/memory/indexes/vectors.sqlite. Delete it and nothing is lost; the next search rebuilds it. Same contract as JIGGA's FTS5 index. - Incremental. A document whose text hasn't changed keeps its vector. Changing the embedder discards the index entirely, because vectors from another model live in a different space and ranking against them is meaningless rather than merely wrong.
- Same visibility rules as the keyword index. Team layers are gated to their
team, scopes restrict to their
includes, and an unrecognised scope returns nothing rather than everything — a backend that failed open would hand an agent the memory the scope existed to withhold. - Brute-force cosine. Correct at this scale: a personal install has thousands of
documents, not millions, and an ANN index would add a dependency and an
approximation to solve a problem that doesn't exist yet.
sqlite-vecor LanceDB is the upgrade path if a corpus grows into it. - Degrades, never fails. If this pack raises, JIGGA's router keeps the keyword
results, reports the reason, and audits
memory.search.degraded.
python -m venv .venv && .venv/bin/pip install -e ".[dev]"
.venv/bin/python -m pytestThe tests don't import JIGGA. That independence is the point of the seam: a backend pack is ordinary Python that JIGGA happens to import, and if these tests needed a JIGGA checkout the dependency would be running the wrong way.
MIT.