Oh is an open-source memory store for agents. It keeps each fact as a record with its sources attached and writes every accepted change to a log you can replay. The notes an agent writes while it works stay apart from the knowledge a person has reviewed, so when an agent tells you something wrong, you can see what it stored, where that came from, and whether anyone checked it.
A memory you can question later
Picture a research assistant that reads a trial report on Monday and tells a colleague on Thursday that the study's primary endpoint was measured at 12 weeks. If the memory is a pile of text chunks in a vector index, the best you can do is search for similar text and hope the right chunk comes back. You can't see which report the claim came from, which table supported it, or whether the agent wrote it before or after someone corrected the source.
Oh stores that same work as linked records. The question, the source, the captured edition of the source, the claim, the evidence that bears on it, and the brief that came out of it are separate records, each with a stable key and a digest of its content. The README walks through this chain:
inquiry:primary-endpoint
→ entity:trial-report
→ edition:trial-report-v1
→ statement:endpoint-12-weeks
→ assertion:endpoint-12-weeks
→ evidence:table-2
→ view:review-briefMonths later you can follow that path back from the brief to the table it rests on. A claim and the act of accepting it are separate records, so "the report says 12 weeks" and "our reviewer accepted that" can be checked one at a time.
Who Oh is for
Oh is for developers building an agent or a knowledge application who need memory that the agent can write to and that people can audit afterwards. It fits research tools, assistants that run over long sessions, and any product where someone will eventually ask "why does the system believe this?"
If what you want is a Markdown notebook that you query, use Wordcell instead. Oh's own README draws that line: use Oh to build an application's memory layer, and Wordcell to maintain and query a Markdown knowledge base.
What Oh does today
Oh ships as a TypeScript SDK, a command-line tool called oh, and an Agent Skill, all sharing one versioned record format. By default, records and their history live in a single local SQLite file, and a libSQL store is available for server runtimes. The first run needs no account, no hosted model, and no remote database. Search indexes are built from the records, and you can delete and rebuild them at any time.
The first run from the README creates one record, reads it back, finds it by keyword, and checks the log:
oh init
oh put \
--kind entity \
--key entity:ada-lovelace \
--json '{"name":"Ada Lovelace","role":"mathematician"}'
oh get entity:ada-lovelace
oh search "mathematician" --mode keyword
oh verifyEvery command except help and oh version prints JSON in Oh's canonical form, described below. oh verify replays the operation log and confirms that each step's digest still matches. When two writers race, the later write fails with a conflict error instead of overwriting the earlier one. Oh's documentation advises reading the new state, reconciling, and submitting again.
Install instructions and the checksum for the current release are in the README.
Working notes and reviewed knowledge stay apart
The memory part of the SDK takes two stores. A working store holds what the agent writes as it goes, and a hosting application can purge it. A second store holds reviewed knowledge, pinned at a known point in its history. The SDK hands your application two separate objects:
- The agent's object has four methods:
remember,query,explain, andnominate. It cannot write to the reviewed store, choose a database, or purge anything. - The host's object, which your trusted code keeps, is the only part of this interface that can move working records into reviewed knowledge. Oh's memory specification requires that a model-facing adapter receive only the agent's object.
When the agent believes something should become reviewed knowledge, it nominates it. Your code, after whatever review you run, adopts the nomination:
// The agent proposes; it cannot commit to reviewed memory itself.
const nomination = await memory.agent.nominate({
nominationId: "knowledge-review",
roots: ["edition:reviewed-summary"],
v: 1,
});
// Trusted host code adopts it after review.
await memory.host.adoptNomination({
expectedCanonicalHead: reviewedHead,
nomination,
v: 1,
});Adoption inserts records that are new and fails if a key already holds different content, unless your code names the exact prior version it means to replace. The agent's writes carry an actor and a timestamp that the host supplies. The agent's object doesn't accept an actor or timestamp from the caller, and the host clock never moves backwards, so a model can't claim to be someone else or backdate a note.
Two implementations of one format
Oh's records use one encoding, canonical JSON: object keys are sorted in a fixed order and each number prints one way. A record's digest is the SHA-256 of its canonical bytes. If two programs encode the same record differently by a single byte, the digests differ and the history no longer verifies.
Oh has a TypeScript reference encoder and a Rust encoder compiled to WebAssembly. The Rust crate is written to produce output byte for byte identical to the TypeScript reference for every plain JSON value the reference accepts. The property the tests check is short:
// Checked on each generated JSON text:
rust.canonicalJson(text) === canonicalJson(JSON.parse(text));
rust.canonicalSha256(text) === canonicalSha256(JSON.parse(text));
// Keys sort; both engines agree on the bytes.
canonicalJson({ b: 1, a: 2 }); // '{"a":2,"b":1}'
// Negative zero is refused by both.
rust.canonicalJson("-0"); // throwsThe parity suite checks this on generated inputs: 1,000 generated documents for the encoding, 1,000 for the digest, and 20,000 generated finite floating-point numbers to check that Rust formats numbers exactly as JavaScript does. The generated documents share one fixed shape (short integer arrays, small string-keyed maps, and a nested flag), and a list of hand-written edge cases covers empty values, escapes, surrogate pairs, and key order. These are samples, so they show agreement on the inputs tested and do not prove it for every possible input. The TypeScript version stays the reference. The Rust engine is optional, and the base package still has no required runtime dependencies. The companion post on keeping the TypeScript and Rust encoders identical goes through the method.
Shared parts for other Hraness products
Oh keeps records and operations in one SQLite file you control. Every accepted change can be inspected through digests and replay, and search and derived answers are treated as views that never become the record.
The Rust foundations plan extends that. It builds the canonical encoding, a strict archive reader, and a rule engine for graph queries in Rust so other Hraness products can reuse them, with WebAssembly as the default and native bindings as an opt-in. The TypeScript implementations stay authoritative until each Rust replacement proves byte-exact parity. Two products already build on Oh, each pinning its own release:
- Sponge keeps its hosted agent's working memory in a server-side Oh store that expires with the session, separate from the product data in Sponge's own databases.
- Wordcell rebuilds a disposable Oh graph from your Markdown to answer named graph queries with source proofs. Markdown and Git stay the record, and search does not use Oh's memory retrieval.
The list of products built on Oh collects these.
Limits of the current release
Oh does not claim to retrieve better than other memory frameworks. Its README states that superiority over Letta, Supermemory, and other frameworks has not been established.
Sync accepts only histories that extend each other. When two copies diverge, sync stops and reports the divergence without merging. Graph answers derived by rules come with proofs, and the store never adopts them as records on its own. The CLI and local SQLite store need Bun 1.3.14 or newer; the libSQL store also runs on Node 24 serverless runtimes. The optional research vocabularies map selected Wikidata properties, not all of Wikidata.
Oh is MIT-licensed and free, with no account required. Latest release: v0.12.0.