Skip to main content

SerenLoci

The left brain. A keyed facts-and-logic store for the Seren constellation - addressable, deterministic, exactly one live value per key.

Where SerenMemory (the right brain) holds fuzzy, episodic memory - "we ground on the embedder migration for a week, it was a slog" - Loci holds facts:

{ project, key, value, why }

camelCase is life. braces on a new line in posh. GGML_CUDA_NO_VMM=ON must be set at compile time - because the env var isn't honored at runtime on Jetson. A locus has an address. You go to it and get the thing - you don't grope around for something that rhymes.


Why it's shaped like this

One live value per key, enforced by the database. Set a new value for a key and the old one is superseded - kept as history, pointed at by the new row, never blended. A vibed-together fact is worse than no fact, so the rule is strict, and it's not enforced by hope: a PARTIAL UNIQUE INDEX makes sqlite physically refuse a second live row per (project, key).

Two tiers. A reserved project of * is the fundamentals tier - cross-project truths. A concrete project name (seren-memory) is the per-project tier - the targeted override. Same split as nano/xavier/dgx prebuilts: the platform-wide truth and the per-board variant.

The why is the point. A logic store without rationale is just a dictionary. The value tells you what; the why is what stops you re-learning it the painful way - and it's searchable, so "that CUDA thing" finds a fact whose reason mentions CUDA even when the key doesn't.


The floor is free

Three access rungs, cheapest first:

  1. Exact - get_fact(project, key) returns the live value, deterministically. No embedding, no ranking. You know the address, you get the thing.
  2. Lexical - FTS5 full-text over (key, value, why) of the live rows. The "I sort of remember the words" path.
  3. Vector (additive) - a sqlite-vec index for the "this smells like that CUDA thing" associative jump. Built only when you name an embedder.

Rungs 1 and 2 need nothing but sqlite (stdlib) and the web stack - no torch, no GPU, the 4GB-laptop floor. The vector finder is the ceiling, opted into by install, never required. Where does it sit? How much does it need? - the floor needs almost nothing.


Install

pip install seren-loci                 # the floor: exact + FTS5 lexical
pip install seren-loci[vector]         # + the sqlite-vec associative finder (pulls torch)
pip install seren-loci[mcp]            # + the MCP surface (model reaches facts directly)
pip install seren-loci[corp]           # + OS-trust-store TLS for corp-proxied boxes

Extras stack: pip install seren-loci[vector,mcp].

Run

seren-loci                             # or: python -m seren_loci
seren-loci --config ./seren-loci.yaml

Listens on 7422 by default (neighbor convention: memory 7420, margin 7421, loci 7422).

# set a fundamental truth
curl -X POST localhost:7422/fact -H 'content-type: application/json' \
  -d '{"key":"posh.brace_style","value":"curly brackets on a new line","why":"readability"}'

# get it back, deterministically
curl 'localhost:7422/fact?key=posh.brace_style'

# discovery search (exact-key first, then the finder)
curl -X POST localhost:7422/search -H 'content-type: application/json' \
  -d '{"query":"cuda runtime"}'

API

Method Path What
POST /fact Set/replace a fact (strict supersede). Names the superseded id, or null.
GET /fact The live value for ?project=&key= (project defaults to *). 404 if none.
GET /fact/history Every value a key has held, newest first.
DELETE /fact Retire (soft-supersede) the live value for a key.
POST /fact/figures Cite an exhibit on the live value ({project, key, source, caption}).
GET /fact/figures The exhibits the live value cites (?project=&key=); /{digest} is the bytes.
DELETE /fact/figures/{digest} Take one off the live value.
GET /facts List facts in scope (?project=&include_superseded=).
GET /counts {live, history, projects, figures}.
POST /search Exact + finder discovery, ranked.
GET / /health Service info / liveness.

Every search hit carries a normalized 0-1 score (exact->1.0, hybrid->RRF fused into 0..1, lexical->bm25 mapped above 0). That's the common currency SerenCorpusCallosum uses to merge left-brain and right-brain results on one axis instead of comparing cosines to key-hits.


Figures: the exhibits a fact cites

A fact can cite a picture - the wiring photo behind "the fan header is the second one", the screenshot behind "the 409 looks like this" - but a figure is never the fact. The fact stays a sentence with a key, searchable, supersedable, with a why; the figure is what the sentence points at: "see figure". So there is no way to put a picture in Loci without saying in words what it proves. set_fact(..., keep=[...]) cites exhibits as the value is set, keep_with_fact adds one to the live value, look_at_fact hands them back as image content, drop_from_fact takes one off. A superseded value keeps its own figures in history; the new value cites what it cites (figure:<digest> cites one the store already holds, without a second copy).

The bytes go in a figures/ folder beside the database under their sha256 and nothing else (seren_sinew.blobs); the row (caption, source, type) is in loci.db. Both ride in the same snapshot, the folder hardlinked from the previous one. Where a figure may be taken from is the figures: block's to say: folders on this box and URL prefixes; nothing listed means nothing can be kept, and the refusal says so.

figures:
  sources:
    - ~/seren/stores/workbench/gallery
    - https://

The hybrid finder (additive - the ceiling, not the floor)

When an embedding model is configured, rung 3 is no longer a pure vector KNN. Instead a _HybridFinder runs both lexical (FTS5) and semantic (vector) search in parallel, then fuses results with Reciprocal Rank Fusion (RRF):

rrf_score(fact) = Σ 1/(k + rank_in_ranker)      # k = 60
                 ranker ∈ {FTS5, vector}

This gives better precision than either ranker alone - FTS5 catches exact/keyword matches with high precision, vector catches semantic matches with high recall, and RRF boosts documents that rank highly in both lists. The old pure-vector path (_VectorFinder) is replaced by _HybridFinder whenever an embedder is present; the floor (no embedder) still uses FTS5 only.

Scope-aware query embedding. When a single project scope is provided (and it isn't the * fundamentals tier), the vector query is augmented by prepending the project name before the raw query string. For example, searching "rate limiting" under project seren-memory embeds "seren-memory: rate limiting" instead - nudging the query vector toward the memory-domain cluster so it disambiguates facts that share wording across projects.


Tests

Test file What it covers
tests/test_store.py 18 tests - strict-supersede invariant, exact lookup, project isolation, FTS5 lexical search, scoping, counts, finder_kind returns "lexical" when no embedder configured
tests/test_routes.py 16 tests - HTTP endpoints, bearer auth, search route returns provenance, GET / reports service + finder kind
tests/test_mcp_tools.py 10 tests - MCP tool surface for set/get/search/forget/list/history
tests/test_mcp_mount.py 4 tests - MCP mount attaches tools and route
tests/test_vector_sql.py 2 tests - sqlite-vec KNN ordering + delete SQL contract (gated on sqlite_vec install)
tests/test_embedder_reconcile.py 8 tests - vector index reconcile/rebuild/backfill logic with a stub embedder (gated on sqlite_vec)
tests/test_hybrid_finder.py 10 tests - RRF fusion boosts docs in both rankers, RRF scores normalised to 0..1, exact still leads, scope-aware query augmentation keeps results in-scope, RRF formula correctness (direct unit test), finder_kind returns "hybrid" when embedder configured, graceful degradation to lexical if embedder import fails, unscoped search finds all projects

Run with pytest (sqlite-vec-gated tests need the [vector] install or a PYTHONPATH into the vector venv's site-packages):

pytest tests/                                    # floor tests (no vector needed)
PYTHONPATH=/path/to/vector-venv/lib/python3.12/site-packages pytest tests/  # all tests

Where it sits in the constellation

  • SerenMemory - the right brain. Fuzzy, consolidated, episodic. General-purpose AI memory protocol.
  • SerenLoci - this. The left brain. Keyed facts, deterministic, strict-supersede.
  • SerenCorpusCallosum - fans a query across both hemispheres and merges on the shared score currency.

Build for the floor, not the ceiling. The Nano is the floor, not the cap. AGPL-3.0-or-later. Rip it and win.

Metadata

Release files for seren-loci 5.1.4

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

Source distribution (sdist)

Source distribution for seren-loci 5.1.4
File Size Uploaded
seren_loci-5.1.4.tar.gz 105.6 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for seren-loci 5.1.4
File Interpreter ABI Platform
seren_loci-5.1.4-py3-none-any.whl Python 3 none any Details

Total release size: 183.1 kB

Release files / seren_loci-5.1.4.tar.gz

Download URL seren_loci-5.1.4.tar.gz
Size 105.6 kB
Tags Source
SHA-256 checksum
How to use checksums
1fa6fc23a303ac25f64bcdfdb987c952cf50d9bbcb1443bca61c1adaab0312b9
BLAKE2b-256 checksum
How to use checksums
294181e7b06a3c3357e0f2825e540bb5cc8fe80ed944d5e9adbd1ba2b2cd08bf
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 16, 2026.

Transparency log

Release files / seren_loci-5.1.4-py3-none-any.whl

Download URL seren_loci-5.1.4-py3-none-any.whl
Size 77.5 kB
Tags Python 3
SHA-256 checksum
How to use checksums
8826d01c584cc9ef702a0b291b0cc7f741bdb6123baebd8b794b9bebe0066faf
BLAKE2b-256 checksum
How to use checksums
c4389e9f4e0d781b646357c54848dd325aa8988f190a17268d09ea5c628c82cb
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 16, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

5.1.4 This release

2 release files

5.1.3

2 release files

5.1.2

2 release files

5.0.1

2 release files

5.0.0

2 release files

2.6.0

2 release files

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