v0.1 · 449 tests · zero dependencies · pre-1.0

One memory.
Many intelligences.

Chitraq is a persistent computational memory. A deterministic core owns identity, versioning, provenance and truth; models work over it and are never allowed to own it. Swap the model, keep the memory — including everything the last one contributed, still labelled as its work.

The idea

Most tools here are storage with search bolted on. Storage answers "where is the file?" Memory has to answer "what do I know, how do I know it, what has changed, and what matters now?"

Knowledge, not documents

A file is kept verbatim as a Source. The claims, decisions and observations inside it become separate objects, each with its own status, evidence and history — so one paragraph can be superseded without rewriting the document it came from.

Provenance never gets lost

Every object records whether you wrote it, a source stated it, an algorithm derived it, or a model produced it. Confirming an AI-derived fact marks it confirmed; it does not relabel it as yours.

History is never rewritten

Editing appends a version. Superseding keeps the old object readable and linked forward. "What did we believe in March?" is a question with an answer. Only an explicit erase, with a stated reason, destroys anything.

Intelligence proposes; you decide

No model writes to memory. A capability returns a value, the value becomes a proposal, and a proposal becomes knowledge only when accepted. There is no second path in — it is enforced in one place and tested.

It answers before it spends

Most questions to a memory are lookups, and a lookup does not need a language model — it needs the sentence you already wrote. Chitraq tries that first, and escalates only when quoting genuinely cannot answer: when nothing matched, when the match is too weak to trust, or when the question asks for synthesis.

Outcomeof 10
answered by quoting your own words6
served from cache2
escalated to a model2

Measured over ten realistic questions. 80% never reached a model. A test counts model calls directly, so a change that quietly starts sending everything to a paid provider fails the suite.

$ chitraq ask "why did we drop the redis cache"

  quoted from your own words        confidence 0.82

  The hit rate never exceeded 30% and the
  memory cost was not worth it.

  from  obj_01J8F… · user · confirmed
  cost  nothing — no model was called
  took  94ms

The cache is keyed on the content hashes of the objects an answer rests on, so editing any of them moves the key. A stale answer cannot be served, because if it could be stale the key already changed.

Get started

# Nothing to install. Node ships SQLite.
git clone https://github.com/Nulfied/Chitraq
cd Chitraq
npm test

# Point it at notes you already have
chitraq ingest ~/Documents/notes

# Then ask
chitraq ask "what did we decide about pricing"

Requires Node 24. There are no dependencies to install — package.json has an empty dependencies block and it is meant to stay that way.

Optional: make it smarter, still free

ollama pull nomic-embed-text   # semantic search
ollama pull moondream          # read images
ollama pull llama3.2           # written answers

Everything runs on your machine at no cost. Without Ollama the built-in deterministic provider still serves every capability — it is the floor the whole system stands on, and the test suite passes with no models installed at all.

Embeddings are the biggest single win: head to head on queries sharing almost no words with the notes, the built-in embedder found 1 of 3 and Ollama found 3 of 3.

One memory, several programs

$ chitraq tokens --new formfit --scope write
import { ChitraqClient } from 'chitraq/client'

const memory = new ChitraqClient({
  url: 'http://127.0.0.1:4317',
  token: process.env.CHITRAQ_TOKEN,
})

await memory.remember({
  title: 'Compress PDFs in the browser',
  kind: 'decision',
})

const answer = await memory.ask(
  'why do we compress client-side'
)

The client is one file with no dependencies. It never caches and never retries blindly — a memory client that quietly returns a stale answer leaves you unable to tell a remembered fact from a remembered response.

Presenting a token constrains you. Presenting nothing changes nothing.

On a loopback install a token cannot make access harder to obtain — anything on the machine could call the API anyway. What it does is make access narrower. A read token is refused a write even where an anonymous caller is allowed one, so a side project can hold a credential that genuinely cannot damage the memory it reads.

ScopeMay
readsearch, ask, recall, entities
writeread, plus capture and review
admineverything, including erase

Measured, not assumed

Two numbers in this codebase were guesses, and both were wrong by orders of magnitude until something measured them. The approximate-index threshold was set at 20,000 vectors; measurement put it at 5,000. A code comment claimed brute-force search was "sub-millisecond at 10k chunks"; it was 152 ms at 12k. scripts/bench-vectors.js exists so the next guess gets caught too.

Vector search

VectorsExactApproxRecall
4004.2 ms0.55 ms1.00
2,00021 ms1.1 ms1.00
6,00056 ms2.3 ms1.00
12,000152 ms12.2 ms1.00

On a laptop with no GPU

OperationTime
quoted answer — the common path70–320 ms
embedding a query~190 ms
reading an image (moondream)3.7 s warm
generated answer (llama3.2)41–50 s

That last row changed a design decision. Escalation uses measured latency, not what an adapter declares — Ollama claims 3 s and takes 45 here. Above the threshold Chitraq answers instantly from your own words and offers the slow one, with the real wait on the button.

What it refuses to do

Guess silently

An image nothing can read is stored verbatim with a note naming the capability that would unlock it. When a model does read it, the source permanently records that its text was read rather than written — a misread "38ms" is indistinguishable from a quote otherwise.

Pick a winner

Where two machines edited the same thing, both are kept and the disagreement is raised. Last-writer-wins destroys one of two real edits with nobody the wiser.

Take a dependency

PDF text extraction, scanned-page images, vector search, hashing and the HTTP server are all written against what Node already ships. Every dependency is a thing that can break, change licence, or be taken over.

And it says where it is weak. Fax-encoded scans cannot be read. Concepts are the shallowest entity kind. The Claude adapter is written and has never run against the live API. Nobody has used this daily for a month. The full list lives in STATUS and is kept current rather than trimmed.

Read further

Status

What is implemented, what is partial, what is deliberately not built — with an honest weaknesses section and every measurement on this page.

Invariants

The sixty rules the code is built to hold, each naming where it is enforced and the test that proves it.

Architecture

How capture, retrieval, context and the intelligence fabric fit together, and why the boundaries fall where they do.