Kerneta/daidocs

Open plain-text file format for AI memory. Your assistant's long-term memory as .dai files on your disk: readable by Claude, GPT, Gemini, Cursor, local models and grep (all LLM models work). MCP server + hooks for Claude Code, Claude Desktop, Cursor, Windsurf, Codex. 83% LongMemEval-S (GPT-4o), 92% (Claude Fable 5), 10x fewer tokens.

22

stars

0

commits

JavaScript

primary language

Sep 15, 2026

updated

daidocs.com
agent-memory
ai-agents
ai-memory
chatgpt
claude
claude-code
context-engineering
cursor
file-format
llm
local-first
longmemeval
long-term-memory
mcp
mcp-server
memory
open-standard
persistent-memory
plain-text

README

English · 简体中文

.dai

An open plain-text format for AI memory (launched Sep 2026).
Your assistant's memory becomes files on your disk that you can open, grep and keep.

Second on the LongMemEval-S leaderboard among memory systems anyone can re-run, 22.40 points above the same model with no memory, reading 10x fewer tokens per question.
Every number here ships with its per-question judge verdicts and a sha256 manifest.

Quickstart · The guide · Benchmark · The format · Reproduce it

Launch release V4.4n32, 12 September 2026. What is in it.

GitHub stars Discord licence: Apache-2.0 node: 18+ MCP: server included LongMemEval-S: 83.00% gpt-4o LongMemEval-S: 92.00% Claude Fable 5 checks: offline, no API key

If .dai is useful to you, a star helps other people find it.

The product in one loop: a one-line install, Claude Code building a site while the files appear in the folder, the memory map, the same six questions answered from a 612k-token history and from DaiDocs reading 3,674,880 against 392,120 tokens, and one .dai file saved by ChatGPT then read along the wires by Gemini and a local model

The whole product, in one loop. Install, build, remember, recall: one store, every model, about a tenth of the tokens. The recording uses invented data.

▶ For higher quality, watch the demo live in your browser


Language independent, model independent

A .dai file is three plain-text zones: a YAML header, a fenced JSON block, and the text. No binary, no database, no SDK required to read it.

  • Any programming language. The reference engine is Node. A reader in Python, Rust or Go is an afternoon's work, and the spec is normative, written so that two independent implementations agree.
  • Any model. The store is written once by a cheap observer model and read by whichever model answers. The same store measured with five answering models: 78% to 92%. Change the model, keep the memory.
  • Any tool. grep, git log, diff, your editor, a shell script. Memory that answers to ordinary tools.

Build a reader in another language and open a PR: that is the contribution that matters most.


What is in this repository: the Kerneta Engine V4.4n that reads and writes .dai files, the MCP server that connects it to your assistants, and the complete evidence for every number quoted below: the benchmark run, the judge's verdict on each of the 500 questions, and the five-model comparison. Each evidence file is hashed in MANIFEST.sha256 so you can check that what is described is what was measured; how to do that is in docs/PROVENANCE.md.

Strict same-setup ranking on LongMemEval-S: Mastra OM 84.80%, .dai v4.4n 83.00%, Supermemory 81.60%, Mastra RAG topK 20 81.20%, EmergenceMem Simple Fast 79.00%, TiMem 76.88%, Zep 71.20%, Feather 69.30%, GPT-4o with Chain-of-Note 64.00%, GPT-4o with no memory system 60.60%

Second on the leaderboard. One setup for every row: LongMemEval-S, GPT-4o answering, all 500 questions, micro-averaged, and only configurations somebody who does not work for the vendor could re-run. The bottom row is that same GPT-4o with no memory system, reading the whole history pasted into its context: 22.40 points below us. Every figure here carries a caveat and the caveat travels with it, in docs/RESULTS.md.

Not in that table? Graphify, Hindsight, Mem0 and the others publish figures measured on a different answering model, a different denominator or a different benchmark, so they cannot be set beside a GPT-4o 500/500 row in either direction. Every one of them is at daidocs.com/results.html, with what its number actually measures and where ours sits against it.

Same stores, same prompts, same judge: five answering models on LongMemEval-S

One memory layer, five answering models, 500 questions each. Retrieval identical for every row (proved by a byte-identical diagnostics file). Details and caveats in RESULTS-ACTORS.md.


Why this exists

Every memory product on the market keeps your history inside its own service and hands it back through its own API. .dai takes the opposite bet: memory is a file format, the way a photo is a JPEG. Three plain-text zones per conversation, a small derived index beside them, and any model, any tool, or grep can read it.

memory as a servicememory as a format (.dai)
where your history livestheir databaseyour disk, plain text
who can read ittheir SDKClaude, GPT, Gemini, Cursor, local models, grep, git
when the vendor disappearsso does the memorythe files stay readable in any editor
how you inspect a recalllogs, if anyopen the file the answer cites
what a benchmark number meansone product's pipelineone store, measured per answering model, so you can pick the model

The store is built once by a cheap observer model and read by any actor model. Convert with a good model, then answer with whatever is cheapest, fastest or local. Numbers below.


Works with

One store, connected over MCP, read and written by the tools you already use. node setup.js detects and configures each of these and backs up what it touches; Install has the per-tool commands.

assistantseditors and IDEsCLI and any MCP client
Claude Desktop, Claude Code, any model over MCPCursor, Windsurf, Zed, Cline, ContinueCodex CLI, plus any MCP client via --client generic --config <file>

Any MCP-capable runtime, too. The server is a plain stdio MCP server, so frameworks that speak MCP call save_memory and recall_memory with no adapter to write: the OpenAI Agents SDK, the Vercel AI SDK, LangGraph, LangChain, CrewAI and LlamaIndex all consume an MCP server as a tool source. Point them at node mcp_server.mjs.

Bring your history. Claude Code sessions on this machine convert automatically. From any other tool, export a folder of .txt, .md or .jsonl and run node daidocs.js convert. Native history import from more tools is on the roadmap.


Install

Node 18 or newer.

npx daidocs setup

One command. It detects Claude Desktop, Claude Code, Cursor, Windsurf, Codex, Cline, Continue and Zed, configures all of them, installs the session hooks, the reading protocol and the .dai icon, and backs up every file it touches. On a Claude subscription there is no API key and nothing to pay.

Want the source and the benchmark artifacts too? Clone it and run setup from there instead:

git clone https://github.com/Kerneta/daidocs daidocs-app
cd daidocs-app
node setup.js

The clone is named daidocs-app on purpose. git clone would otherwise make a folder called daidocs, and the default memory store is DaiDocs: on Windows and macOS those are the same folder, so a clone made from your home directory would land on top of your own memory. Setup refuses to run from inside the store if it ever happens.

Python (pip)

Prefer Python? Read your .dai stores from code, and drive the engine from a daidocs command:

pip install daidocs
from daidocs import Store

store = Store("~/DaiDocs")          # your memory store
for entry in store.manifest():      # every document
    print(entry["id"], entry["title"])

doc = store.read(store.ids()[0])    # one document, fully parsed
print(doc["understanding"]["summary"])
print(store.search("deploy"))       # find documents by keyword

Two things in one install:

  • Reader (pure Python, no Node): from daidocs import Store reads the manifest, any document, and the facts / events / profile indexes.
  • daidocs command: drives the Node engine, so daidocs setup and daidocs convert behave like npx daidocs. This needs Node 18+; if Node is missing it says so and offers to install it. Full guide: readers/python/.

setup.js installs the dependencies on its first run and then configures everything. npm run setup does the same thing, but node setup.js is the one to reach for on Windows: PowerShell refuses to run npm at all until you change its execution policy, and node is not affected by that. Each line above is its own command, because Windows PowerShell 5.1 has no &&.

Setup asks nothing. It detects what you have and configures all of it: Claude Desktop, Claude Code, the session hooks, Cursor, Windsurf, Codex, Cline, Continue, Zed, the reading protocol and the .dai file icon. It backs up every file it touches.

node setup.js --status     what is on, and the command that changes each one
node setup.js --ask        choose each surface yourself instead
node setup.js --restore    put the machine back exactly as it was

The one thing it never does on its own is convert the history you already have, because that can run for a while and, with an API key, it spends money. It is one command when you want it, and it is worth wanting: see Bring what you already have.

Another MCP client? One command each, rather than a config to edit: node setup.js --client codex (or cursor, windsurf, cline, continue, zed), and node setup.js --client generic --config <that client's config file> for anything else. node setup.js --client list shows the names and where each one keeps its config.

In Claude Code every session saves itself as you work, so there is nothing to remember. On any other connected assistant, say "save this chat to memory". To give a folder its own project memory, say "make this folder a project" in it, or in a subfolder to make a sub-project.

Bring what you already have

Most people installing this have months of conversations sitting on disk already. One command turns them into memory, which is the difference between a store that is useful this afternoon and one that fills up slowly from here:

node daidocs.js convert

It reads three kinds of history, all the same way:

  • Claude Code sessions on this machine, from ~/.claude/projects
  • Sessions already captured but not yet converted, the _pending markers with their text in _unconverted/
  • A folder of exports from anywhere else: .txt, .md or .jsonl

It lists what it found with dates, projects and sizes, asks which ones (all, or 1,3,5-8), asks where the store goes, and quotes the worst-case token count and cost before any paid call. On a Claude subscription that cost is nothing: the assistant in the session writes the extraction itself. Each item is written the moment it finishes, so a crash loses at most one document and re-running skips whatever is already converted. Sessions land in the folder they came from, so a project's history ends up in that project's own store rather than in one pile.

Every question has a flag, so it scripts:

node daidocs.js convert --source claude --project atlas-api --pick 1-5 --to ~/DaiDocs --yes

The guide lists every flag.

After that it is automatic

You do not have to remember to save anything. Once the hook is installed, every session saves itself:

  • Every 4,000 new tokens, the session so far is converted in the background, into the folder you are working in. It is written by the assistant already in the conversation, so it costs no API key and no extra call.
  • Close the terminal earlier than that and nothing is lost. After every reply the not-yet-converted text is written to _unconverted/ in the folder's store, so even a killed terminal loses at most the last exchange. Open a session in that folder again and that text is read in at the start, verbatim, and recall_memory reads it too, so a 2k session is usable before it is converted. What is waiting counts towards the next save, so yesterday's 2k and today's 2k convert together, and the folder empties as they do.
  • The first time you open a session in a folder, you are asked one question before anything else: keep this folder's memory here, as a project of its own, or in the general store with everything else? Either answer is remembered, so you are not asked again for that folder.

So the only thing you do is work. The guide has the detail, and the diagram further down shows the whole path.


What you get

A folder. That is the whole trick.

~/DaiDocs/
├── 2026-07-12_deploy-debug.dai     one file per conversation, three zones
├── 2026-07-18_q3-planning.dai
├── _index/                         what retrieval reads: manifest, facts, events, profile
├── _unconverted/                   what is not converted yet, small, read by the next session
└── _raw/                           your originals, byte-exact, never deleted

There is no database, no memory server and no vendor holding your history. One store serves Claude, GPT, Gemini, Cursor and local models, and it stays readable when any of them is gone.

Which means your memory answers to ordinary tools:

$ grep -l "Casa do Rio" ~/DaiDocs/*.dai
/home/you/DaiDocs/chat_20260720_e0546121.dai

$ head -12 ~/DaiDocs/chat_20260720_e0546121.dai
---
daidocs: "4.4"
id: "chat_20260720_e0546121"
type: "chat"
title: "Valletta trip planning chat"
lang: "en"
source: {"app": "claude", "native_id": "chat_20260720_e0546121"}
span: null
messages: 3
class: {"category": "general", "priority": "normal", "actionable": false, "sensitivity": "public", "confidence": 0.9}
summary: "User booked a summer trip to Valletta staying at the Casa do Rio guesthouse."
tags: ["x.travel"]

No client, no query language, no export step. git log your memory if you want to.

And a map of it, when you want to look

npm run dashboard
A click-through of the memory map: every store and what it costs on disk, the conversion backlog grouped by project, a store's memories and the lines between related ones, a memory as its own page, the file in its three zones plus the verbatim original, live search, the folder page with backup and folder type, and the project file tree

A click-through of the map: every store with its folder type and cost on disk, a store's memories with the lines between related ones, a memory as its own page, and the file in its three zones beside the untouched original. Built from your own files into one self-contained page that works offline. The recording uses invented data.

To open it: in the install folder run npm run dashboard. It writes daidocs-dashboard.html beside package.json and opens it in your default browser. One file, offline, no server. Pass --no-open if you would rather it just told you the path.

It is a snapshot, so it shows what was there when it was built. To keep it current while you work:

npm run dashboard-live

That rebuilds the page whenever a store changes, and the page reloads itself when you have stopped touching it, landing back in the store you were looking at. It never reloads mid-read or while you are clicking.

Nothing is lost when a session is short

What happens to a session: at every stop the hook checks for 4,000 new tokens; over the threshold it converts immediately, under it the unconverted text goes to _unconverted with a marker in _pending, is read in when you next open that folder, and converts when it is worth a memory

Under 4,000 new tokens a session is not converted yet. Its text is written to _unconverted/ in the folder's store, and the next session in that folder starts with it in front of the assistant, verbatim, so nothing said is lost or unreadable; recall_memory reads it too. Closing the terminal changes nothing: the text and its marker are files on disk. Convert a backlog whenever you like, a project at a time, and each one lands in the folder it came from. The moment one converts, it leaves _unconverted/. The guide has the detail.

Memory belongs to the folder it is about

The seven folder types: normal, locked, frozen, connected, shared, confidential and temporary, with what each one does to that folder's memory

Declare a folder and its memory lives inside it and travels with it. What the folder is then decides what happens to that memory: a locked folder keeps what it has and accepts nothing new, a frozen one is finished, a confidential one is never included in any wider read. Say it in a session, set it in the map, or pass --project-type.

Do not wait to be asked. In a Claude Code session in the folder, type make this folder a project; that is the whole instruction. A project with several parts, a website, an app, is several projects: make this folder a project that reads its parts at the top, make this folder a project in each part, so a session loads only its part's memory, and look in the main project's memory too when a part needs it; it asks once. The guide has it step by step.


Does it work

83.00% (415/500) on LongMemEval-S: 500 questions over chat histories averaging 103,601 tokens, measured by the adapter in this repository (benchmark/run_longmemeval.mjs) on stores built fresh from the dataset, scored by the benchmark authors' own evaluate_qa.py with judge snapshot gpt-4o-2024-08-06, GPT-4o answering. Task-averaged: 84.02%.

docs/RESULTS.md holds the full conditions, the per-category breakdown including the weakest rows, and the disclosure of everything that was shaped by developing against this benchmark.

The engine reads a small, question-specific slice of the store instead of the whole history: 10,065 tokens per question against a 103,601-token history, about 10.3x fewer, counted with the same tokenizer on both sides. Retrieval is almost all code over an index; its one external dependency is a disk-cached text-embedding-3-small call that ranks what the reading model sees (counting and advice reads make a second call over candidate facts).

Second on the benchmark, among memory systems whose configuration can be reproduced by someone who does not work for the vendor. One system publishes a higher figure: Mastra Observational Memory at 84.80%, which is 1.80 points and 9 questions ahead on the same GPT-4o actor, a gap inside single-run noise at n=500 (standard error 1.68 points). Against the benchmark authors' own full-context baseline, the same model reading the pasted history, it is 22.40 points ahead. The full table, the rule that decides who is in it, and the caveat each figure carries are in docs/RESULTS.md; the figures themselves are recorded as data with their sources in tools/references.json.

The engine routes a question to one of four reading strategies (lookup, tally, timeline, advice) with a regex classifier over the question text. Whether that is tailored to the benchmark is a fair question with a checkable answer: the classifier reads the question text only, has no access to the dataset, and no caller can override it. Print it from the shipped source and measure it yourself:

node tools/verify_router.mjs /path/to/longmemeval_s.json

What that measurement can and cannot rule out.

One memory layer, five answering models

The store is portable across models; the score is not. So the same 500 questions were answered again with everything held fixed (same stores, same rendered prompts, same regex routing, same judge) and only the answering model swapped:

actoraccuracycorrect+/- 1 s.e.task-averaged
Claude Fable 592.00%460/5001.2191.94%
Claude Opus 591.00%455/5001.2890.94%
Claude Sonnet 585.60%428/5001.5786.75%
openai:gpt-4o (release run)83.00%415/5001.6884.02%
Claude Haiku 4.578.00%390/5001.8577.66%
openai:gpt-4o, no memory system60.60%303/5002.19not published

The last row is the same model with no memory layer at all: the benchmark authors' own full-context baseline, where the entire history is pasted into the context window and the model answers from that. It is their measurement on their harness, not a run of ours. Its count and standard error are arithmetic on that published percentage at n = 500, by the same formula that gives every other row its s.e.; the task-averaged column is left open because it needs the six per-type accuracies and they published one overall figure. Read against our gpt-4o row it is the cleanest comparison available, because the actor is identical and the only variable is the memory: 83.00% against 60.60%, a gap of 22.40 points, and it is the row that costs the most to run, since pasting the history is what a 100,000-token prompt per question means.

Fable 5 and Opus 5 are inside one standard error of each other and should be read as tied. The whole spread sits in multi-session synthesis (88.72% down to 69.92%); retrieval was identical for every row, proved by a byte-identical per-question diagnostics file. The Claude rows were produced through the manual provider route rather than the API, which is a real difference and is disclosed in full in RESULTS-ACTORS.md.

Retrieval, measured on its own

A retrieval-only sweep re-reads the same 500 questions at k = 1 to 15 with no model call at all: content recall is 96% at k=1 and 98% from k=3 onward, and nothing above k=5 moves it. The shipped operating point (k=5, 10,065 tokens) is where the curve is already flat. Multi-session sits at 99% content recall and 72.18% accuracy with gpt-4o, which is the clearest evidence that the remaining errors are reading errors, not search errors.

Recall at k on LongMemEval-S

Full tables, both recall definitions, and the zero-network-call proof are in experiments/recall-sweep/.


When it earns its place, and when it does not

Below roughly 20k tokens of history there is not much to save. You are asking a few questions and the whole conversation still fits in the window, so the raw text is what gets used and DaiDocs is not doing much for you. Past that point the history stops fitting, and the .dai store is what keeps the answers available. The background conversion runs either way, every 4,000 tokens, so by the time you cross that line the store is already there.

Agent traces are the one shape it does not handle well. Tool calls, stack traces and file dumps look nothing like conversation, and converting them today produces poor stores. That is a real gap and it is being worked on.

Want it run for you? The engine here is the whole engine and always will be, self-hosted and free under Apache-2.0. If you would rather not operate it, we host it: conversion, storage and recall as a managed service, same format, same files, exportable at any time. That is how the work here gets funded. See daidocs.com.


Choosing your model

Setup asks you once, at install, and that choice then applies everywhere. Conversion, the hooks, the MCP server and the CLI all use it until you change it.

On a Claude subscription, in Claude Code: use Opus. It is what we recommend, and on a subscription the conversion is written by the assistant already in the conversation, so there is no API key and nothing extra to pay.

With an API key: use openai:gpt-4.1-mini. Low cost, high accuracy, and it is the observer every published number in this repository was measured with. gemini:gemini-3.1-pro is the other good choice.

Conversion is cheap in tokens. Converting a session costs roughly what the session already occupies plus a question or two at that same size. It is not a second pass over your whole history; it reads what is new, once.

Go higher if you like, but do not go lower. The observer's output is baked into the file permanently, so every future answer is limited by what it captured the first time. A model that captures 65% of what mattered instead of 96% does not give you slightly worse recall later: it gives you a store that no longer contains the answer. The five-model comparison above is the measured version of that: the same store, the same questions, and a 14-point spread purely from who is reading.

The answering model is the cheap decision and can change per question. The observer is the one worth spending on, because you only get to run it once.


Using it

Six tools over MCP: save_memory, recall_memory, list_memories, read_memory, declare_project and brief_parent. You never call them; you ask naturally:

  • "save this chat to memory"
  • "what did we decide about the deploy pipeline?"

With the Claude Code hooks installed, every session saves itself as you work, with nothing to remember.

Reading a store efficiently is a separate step from connecting one, and it is the step people skip. Loading whole .dai files instead of the three zooms costs an order of magnitude more tokens for no accuracy gain. setup.js installs the protocol into ~/.claude/CLAUDE.md for you; the same rules are in prompts/READER-PROMPT.txt to paste into any assistant.

node daidocs.js ingest ./my-chats ./my-store    # convert a folder
npm run check                                    # verify an install, no API key needed
variabledefaultwhat it does
DAIDOCS_STORE~/DaiDocswhere the store lives
DAIDOCS_OBSERVERthe model you chose at installoverrides that choice for one run
DAIDOCS_DISABLEunsetskip the auto-archive hook
DAIDOCS_NO_PINGunsetrefuse the one-time opt-in install ping without being asked

Reproduce our numbers

You reproduce the number by running it, not by downloading our answer file. Three things, all public: the dataset (LongMemEval-S), the engine (lib/methods/daidocs-v44n, in this repo), and the scorer (the benchmark authors' own evaluate_qa.py). Protocol in docs/REPLICATION.md.

Per-question outcomes are in benchmark/ so you can find which questions differ rather than comparing two totals. If you cannot reproduce a number, that is the most valuable issue you can open, and we will say so publicly rather than quietly editing the page.


Repo map

pathwhat it is
QUICKSTART.mdfive minutes, nothing assumed
spec/DAIDOCS-STANDARD.mdthe .dai format specification
docs/RESULTS.mdthe conditions, the disclosures, and every number once measured
docs/REPLICATION.mdhow to reproduce them
docs/READ-DAIDOCS.mdthe reading protocol, per surface
docs/INTEGRATION.mdusing it with Claude Code: hooks, converting history, keyless saving
prompts/the protocol as a paste-anywhere prompt
daidocs.jsthe CLI: convert, pending, stores, backup, scrub, ingest, ask
setup.jsone-command install and configuration
lib/methods/daidocs-v44n/the engine, in the configuration this repo ships
mcp_server.mjsthe MCP server
session_archiver.mjsthe Claude Code SessionEnd hook
session_context.mjsthe SessionStart hook: memory loads at the start of a session
session_autosave.mjsthe Stop hook: sessions save themselves, with no API key
verify_surfaces.mjsnpm run verify: every surface, free and offline
keyless_check.mjsproves nothing needs an API key to run
lock.jsnpm run lock: makes this folder read-only
assets/the brand marks, the charts, the diagrams and the demo
benchmark/run_longmemeval.mjsthe benchmark adapter, so the run is checkable
benchmark/per-question results
RESULTS-SUMMARY.mdthe release run, gpt-4o, in one page
RESULTS-ACTORS.mdfive answering models over the identical memory layer
run-artifacts/answers, judge verdicts, diagnostics and the run manifest, per actor
experiments/recall-sweep/recall@k, k = 1 to 15, retrieval only, zero API calls
MANIFEST.sha256sha256 of every file as frozen; docs/PROVENANCE.md says how to verify
docs/GAPS.mdthe honest list of what has not been done
tools/verify_router.mjsprints the router from source and measures it
tools/check_numbers.mjsfails CI if any published number drifts from the artifacts
tools/make_charts.pyregenerates the charts from the numbers
tools/chart_theme.pythe daidocs.com chart surface, ported to matplotlib
tools/make_diagrams.pyregenerates the explainer diagrams
tools/dashboard/npm run dashboard: builds the memory map. A built page is never shipped
docs/GUIDE.mdevery command, tool, script and folder type, in one page
tools/make_badges.pythe badges at the top, as local files rather than fetched
CHANGELOG.mdwhat changed, per release
SECURITY.mdhow to report something, and what is in scope
RUNBOOK.mdthe release run, step by step

Contributing

The format is the point, so the most useful contributions are the ones that put it in more places.

Integrations. A store that only one assistant can read is not a format, it is a database with extra steps. The MCP server covers Claude Desktop, Claude Code, Cursor and Windsurf. Everything else is open: an extension for another editor, a plugin for another agent framework, a loader for another runtime, an adapter for an assistant that speaks something other than MCP. If you are wiring one up and something in the format fights you, that is a bug in the format and worth an issue. Two we want by name: an OpenRouter provider backend, one key and hundreds of models, which turns bring-your-own-model into a line of config and slots into lib/providers/ beside anthropic, openai and gemini with the same small contract; and a Hermes agent integration, so someone running that stack can point it at a store and have memory work.

A second implementation. A reader or writer that is not this code. It is deliberately small enough to write in an afternoon: UTF-8, a YAML header, a JSON zone and text. Two independent implementations is the difference between a file layout and a format.

Improvements to the memory itself. Better extraction, better retrieval, better handling of the shapes that do not work yet. Agent traces are the obvious one: tool calls and stack traces convert badly today and somebody solving that would be solving it for everyone. Anything that makes recall more accurate, or makes a store cheaper to read, is welcome.

Bugs and rough edges. Especially on macOS and Linux, which are audited but much less used than Windows here. If something is confusing rather than broken, that is still worth reporting: a feature nobody can find is a feature that does not exist.

Small changes are welcome without asking first. For anything that changes the format itself, open an issue before writing code, because that is the part other people's work depends on staying still.

By contributing you agree your work is licensed under Apache-2.0, and you sign off that you have the right to submit it (DCO).


Counting installs, opt-in and off by default

DaiDocs is local-first, and the tool sends nothing on its own. There is exactly one exception, a single install ping, and it is built to keep that promise rather than bend it:

  • It is asked once, on the first interactive setup, and never again.
  • The default is no: a bare Enter declines, and it never prompts on a non-interactive run.
  • A yes sends one anonymous request: a random id, the version and a timestamp. Nothing that identifies you, your files or your memory.
  • DAIDOCS_NO_PING=1 refuses it outright, without being asked.
  • The choice is recorded in ~/.daidocs/install.json; delete that file to be asked again.

It exists so the project can count how many people install it. If you would rather it did not exist at all, that one variable turns it off for good.


Licence

The specification, the engine and the MCP server are Apache-2.0, including a patent grant. Commercial use, modification and redistribution are all fine. There is no lagging free edition: what is published here is what runs.

Built by Kerneta.

Kerneta/daidocs

Open plain-text file format for AI memory. Your assistant's long-term memory as .dai files on your disk: readable by Claude, GPT, Gemini, Cursor, local models and grep (all LLM models work). MCP server + hooks for Claude Code, Claude Desktop, Cursor, Windsurf, Codex. 83% LongMemEval-S (GPT-4o), 92% (Claude Fable 5), 10x fewer tokens.

22

stars

0

commits

JavaScript

primary language

Sep 15, 2026

updated

daidocs.com
agent-memory
ai-agents
ai-memory
chatgpt
claude
claude-code
context-engineering
cursor
file-format
llm
local-first
longmemeval
long-term-memory
mcp
mcp-server
memory
open-standard
persistent-memory
plain-text

README

English · 简体中文

.dai

An open plain-text format for AI memory (launched Sep 2026).
Your assistant's memory becomes files on your disk that you can open, grep and keep.

Second on the LongMemEval-S leaderboard among memory systems anyone can re-run, 22.40 points above the same model with no memory, reading 10x fewer tokens per question.
Every number here ships with its per-question judge verdicts and a sha256 manifest.

Quickstart · The guide · Benchmark · The format · Reproduce it

Launch release V4.4n32, 12 September 2026. What is in it.

GitHub stars Discord licence: Apache-2.0 node: 18+ MCP: server included LongMemEval-S: 83.00% gpt-4o LongMemEval-S: 92.00% Claude Fable 5 checks: offline, no API key

If .dai is useful to you, a star helps other people find it.

The product in one loop: a one-line install, Claude Code building a site while the files appear in the folder, the memory map, the same six questions answered from a 612k-token history and from DaiDocs reading 3,674,880 against 392,120 tokens, and one .dai file saved by ChatGPT then read along the wires by Gemini and a local model

The whole product, in one loop. Install, build, remember, recall: one store, every model, about a tenth of the tokens. The recording uses invented data.

▶ For higher quality, watch the demo live in your browser


Language independent, model independent

A .dai file is three plain-text zones: a YAML header, a fenced JSON block, and the text. No binary, no database, no SDK required to read it.

  • Any programming language. The reference engine is Node. A reader in Python, Rust or Go is an afternoon's work, and the spec is normative, written so that two independent implementations agree.
  • Any model. The store is written once by a cheap observer model and read by whichever model answers. The same store measured with five answering models: 78% to 92%. Change the model, keep the memory.
  • Any tool. grep, git log, diff, your editor, a shell script. Memory that answers to ordinary tools.

Build a reader in another language and open a PR: that is the contribution that matters most.


What is in this repository: the Kerneta Engine V4.4n that reads and writes .dai files, the MCP server that connects it to your assistants, and the complete evidence for every number quoted below: the benchmark run, the judge's verdict on each of the 500 questions, and the five-model comparison. Each evidence file is hashed in MANIFEST.sha256 so you can check that what is described is what was measured; how to do that is in docs/PROVENANCE.md.

Strict same-setup ranking on LongMemEval-S: Mastra OM 84.80%, .dai v4.4n 83.00%, Supermemory 81.60%, Mastra RAG topK 20 81.20%, EmergenceMem Simple Fast 79.00%, TiMem 76.88%, Zep 71.20%, Feather 69.30%, GPT-4o with Chain-of-Note 64.00%, GPT-4o with no memory system 60.60%

Second on the leaderboard. One setup for every row: LongMemEval-S, GPT-4o answering, all 500 questions, micro-averaged, and only configurations somebody who does not work for the vendor could re-run. The bottom row is that same GPT-4o with no memory system, reading the whole history pasted into its context: 22.40 points below us. Every figure here carries a caveat and the caveat travels with it, in docs/RESULTS.md.

Not in that table? Graphify, Hindsight, Mem0 and the others publish figures measured on a different answering model, a different denominator or a different benchmark, so they cannot be set beside a GPT-4o 500/500 row in either direction. Every one of them is at daidocs.com/results.html, with what its number actually measures and where ours sits against it.

Same stores, same prompts, same judge: five answering models on LongMemEval-S

One memory layer, five answering models, 500 questions each. Retrieval identical for every row (proved by a byte-identical diagnostics file). Details and caveats in RESULTS-ACTORS.md.


Why this exists

Every memory product on the market keeps your history inside its own service and hands it back through its own API. .dai takes the opposite bet: memory is a file format, the way a photo is a JPEG. Three plain-text zones per conversation, a small derived index beside them, and any model, any tool, or grep can read it.

memory as a servicememory as a format (.dai)
where your history livestheir databaseyour disk, plain text
who can read ittheir SDKClaude, GPT, Gemini, Cursor, local models, grep, git
when the vendor disappearsso does the memorythe files stay readable in any editor
how you inspect a recalllogs, if anyopen the file the answer cites
what a benchmark number meansone product's pipelineone store, measured per answering model, so you can pick the model

The store is built once by a cheap observer model and read by any actor model. Convert with a good model, then answer with whatever is cheapest, fastest or local. Numbers below.


Works with

One store, connected over MCP, read and written by the tools you already use. node setup.js detects and configures each of these and backs up what it touches; Install has the per-tool commands.

assistantseditors and IDEsCLI and any MCP client
Claude Desktop, Claude Code, any model over MCPCursor, Windsurf, Zed, Cline, ContinueCodex CLI, plus any MCP client via --client generic --config <file>

Any MCP-capable runtime, too. The server is a plain stdio MCP server, so frameworks that speak MCP call save_memory and recall_memory with no adapter to write: the OpenAI Agents SDK, the Vercel AI SDK, LangGraph, LangChain, CrewAI and LlamaIndex all consume an MCP server as a tool source. Point them at node mcp_server.mjs.

Bring your history. Claude Code sessions on this machine convert automatically. From any other tool, export a folder of .txt, .md or .jsonl and run node daidocs.js convert. Native history import from more tools is on the roadmap.


Install

Node 18 or newer.

npx daidocs setup

One command. It detects Claude Desktop, Claude Code, Cursor, Windsurf, Codex, Cline, Continue and Zed, configures all of them, installs the session hooks, the reading protocol and the .dai icon, and backs up every file it touches. On a Claude subscription there is no API key and nothing to pay.

Want the source and the benchmark artifacts too? Clone it and run setup from there instead:

git clone https://github.com/Kerneta/daidocs daidocs-app
cd daidocs-app
node setup.js

The clone is named daidocs-app on purpose. git clone would otherwise make a folder called daidocs, and the default memory store is DaiDocs: on Windows and macOS those are the same folder, so a clone made from your home directory would land on top of your own memory. Setup refuses to run from inside the store if it ever happens.

Python (pip)

Prefer Python? Read your .dai stores from code, and drive the engine from a daidocs command:

pip install daidocs
from daidocs import Store

store = Store("~/DaiDocs")          # your memory store
for entry in store.manifest():      # every document
    print(entry["id"], entry["title"])

doc = store.read(store.ids()[0])    # one document, fully parsed
print(doc["understanding"]["summary"])
print(store.search("deploy"))       # find documents by keyword

Two things in one install:

  • Reader (pure Python, no Node): from daidocs import Store reads the manifest, any document, and the facts / events / profile indexes.
  • daidocs command: drives the Node engine, so daidocs setup and daidocs convert behave like npx daidocs. This needs Node 18+; if Node is missing it says so and offers to install it. Full guide: readers/python/.

setup.js installs the dependencies on its first run and then configures everything. npm run setup does the same thing, but node setup.js is the one to reach for on Windows: PowerShell refuses to run npm at all until you change its execution policy, and node is not affected by that. Each line above is its own command, because Windows PowerShell 5.1 has no &&.

Setup asks nothing. It detects what you have and configures all of it: Claude Desktop, Claude Code, the session hooks, Cursor, Windsurf, Codex, Cline, Continue, Zed, the reading protocol and the .dai file icon. It backs up every file it touches.

node setup.js --status     what is on, and the command that changes each one
node setup.js --ask        choose each surface yourself instead
node setup.js --restore    put the machine back exactly as it was

The one thing it never does on its own is convert the history you already have, because that can run for a while and, with an API key, it spends money. It is one command when you want it, and it is worth wanting: see Bring what you already have.

Another MCP client? One command each, rather than a config to edit: node setup.js --client codex (or cursor, windsurf, cline, continue, zed), and node setup.js --client generic --config <that client's config file> for anything else. node setup.js --client list shows the names and where each one keeps its config.

In Claude Code every session saves itself as you work, so there is nothing to remember. On any other connected assistant, say "save this chat to memory". To give a folder its own project memory, say "make this folder a project" in it, or in a subfolder to make a sub-project.

Bring what you already have

Most people installing this have months of conversations sitting on disk already. One command turns them into memory, which is the difference between a store that is useful this afternoon and one that fills up slowly from here:

node daidocs.js convert

It reads three kinds of history, all the same way:

  • Claude Code sessions on this machine, from ~/.claude/projects
  • Sessions already captured but not yet converted, the _pending markers with their text in _unconverted/
  • A folder of exports from anywhere else: .txt, .md or .jsonl

It lists what it found with dates, projects and sizes, asks which ones (all, or 1,3,5-8), asks where the store goes, and quotes the worst-case token count and cost before any paid call. On a Claude subscription that cost is nothing: the assistant in the session writes the extraction itself. Each item is written the moment it finishes, so a crash loses at most one document and re-running skips whatever is already converted. Sessions land in the folder they came from, so a project's history ends up in that project's own store rather than in one pile.

Every question has a flag, so it scripts:

node daidocs.js convert --source claude --project atlas-api --pick 1-5 --to ~/DaiDocs --yes

The guide lists every flag.

After that it is automatic

You do not have to remember to save anything. Once the hook is installed, every session saves itself:

  • Every 4,000 new tokens, the session so far is converted in the background, into the folder you are working in. It is written by the assistant already in the conversation, so it costs no API key and no extra call.
  • Close the terminal earlier than that and nothing is lost. After every reply the not-yet-converted text is written to _unconverted/ in the folder's store, so even a killed terminal loses at most the last exchange. Open a session in that folder again and that text is read in at the start, verbatim, and recall_memory reads it too, so a 2k session is usable before it is converted. What is waiting counts towards the next save, so yesterday's 2k and today's 2k convert together, and the folder empties as they do.
  • The first time you open a session in a folder, you are asked one question before anything else: keep this folder's memory here, as a project of its own, or in the general store with everything else? Either answer is remembered, so you are not asked again for that folder.

So the only thing you do is work. The guide has the detail, and the diagram further down shows the whole path.


What you get

A folder. That is the whole trick.

~/DaiDocs/
├── 2026-07-12_deploy-debug.dai     one file per conversation, three zones
├── 2026-07-18_q3-planning.dai
├── _index/                         what retrieval reads: manifest, facts, events, profile
├── _unconverted/                   what is not converted yet, small, read by the next session
└── _raw/                           your originals, byte-exact, never deleted

There is no database, no memory server and no vendor holding your history. One store serves Claude, GPT, Gemini, Cursor and local models, and it stays readable when any of them is gone.

Which means your memory answers to ordinary tools:

$ grep -l "Casa do Rio" ~/DaiDocs/*.dai
/home/you/DaiDocs/chat_20260720_e0546121.dai

$ head -12 ~/DaiDocs/chat_20260720_e0546121.dai
---
daidocs: "4.4"
id: "chat_20260720_e0546121"
type: "chat"
title: "Valletta trip planning chat"
lang: "en"
source: {"app": "claude", "native_id": "chat_20260720_e0546121"}
span: null
messages: 3
class: {"category": "general", "priority": "normal", "actionable": false, "sensitivity": "public", "confidence": 0.9}
summary: "User booked a summer trip to Valletta staying at the Casa do Rio guesthouse."
tags: ["x.travel"]

No client, no query language, no export step. git log your memory if you want to.

And a map of it, when you want to look

npm run dashboard
A click-through of the memory map: every store and what it costs on disk, the conversion backlog grouped by project, a store's memories and the lines between related ones, a memory as its own page, the file in its three zones plus the verbatim original, live search, the folder page with backup and folder type, and the project file tree

A click-through of the map: every store with its folder type and cost on disk, a store's memories with the lines between related ones, a memory as its own page, and the file in its three zones beside the untouched original. Built from your own files into one self-contained page that works offline. The recording uses invented data.

To open it: in the install folder run npm run dashboard. It writes daidocs-dashboard.html beside package.json and opens it in your default browser. One file, offline, no server. Pass --no-open if you would rather it just told you the path.

It is a snapshot, so it shows what was there when it was built. To keep it current while you work:

npm run dashboard-live

That rebuilds the page whenever a store changes, and the page reloads itself when you have stopped touching it, landing back in the store you were looking at. It never reloads mid-read or while you are clicking.

Nothing is lost when a session is short

What happens to a session: at every stop the hook checks for 4,000 new tokens; over the threshold it converts immediately, under it the unconverted text goes to _unconverted with a marker in _pending, is read in when you next open that folder, and converts when it is worth a memory

Under 4,000 new tokens a session is not converted yet. Its text is written to _unconverted/ in the folder's store, and the next session in that folder starts with it in front of the assistant, verbatim, so nothing said is lost or unreadable; recall_memory reads it too. Closing the terminal changes nothing: the text and its marker are files on disk. Convert a backlog whenever you like, a project at a time, and each one lands in the folder it came from. The moment one converts, it leaves _unconverted/. The guide has the detail.

Memory belongs to the folder it is about

The seven folder types: normal, locked, frozen, connected, shared, confidential and temporary, with what each one does to that folder's memory

Declare a folder and its memory lives inside it and travels with it. What the folder is then decides what happens to that memory: a locked folder keeps what it has and accepts nothing new, a frozen one is finished, a confidential one is never included in any wider read. Say it in a session, set it in the map, or pass --project-type.

Do not wait to be asked. In a Claude Code session in the folder, type make this folder a project; that is the whole instruction. A project with several parts, a website, an app, is several projects: make this folder a project that reads its parts at the top, make this folder a project in each part, so a session loads only its part's memory, and look in the main project's memory too when a part needs it; it asks once. The guide has it step by step.


Does it work

83.00% (415/500) on LongMemEval-S: 500 questions over chat histories averaging 103,601 tokens, measured by the adapter in this repository (benchmark/run_longmemeval.mjs) on stores built fresh from the dataset, scored by the benchmark authors' own evaluate_qa.py with judge snapshot gpt-4o-2024-08-06, GPT-4o answering. Task-averaged: 84.02%.

docs/RESULTS.md holds the full conditions, the per-category breakdown including the weakest rows, and the disclosure of everything that was shaped by developing against this benchmark.

The engine reads a small, question-specific slice of the store instead of the whole history: 10,065 tokens per question against a 103,601-token history, about 10.3x fewer, counted with the same tokenizer on both sides. Retrieval is almost all code over an index; its one external dependency is a disk-cached text-embedding-3-small call that ranks what the reading model sees (counting and advice reads make a second call over candidate facts).

Second on the benchmark, among memory systems whose configuration can be reproduced by someone who does not work for the vendor. One system publishes a higher figure: Mastra Observational Memory at 84.80%, which is 1.80 points and 9 questions ahead on the same GPT-4o actor, a gap inside single-run noise at n=500 (standard error 1.68 points). Against the benchmark authors' own full-context baseline, the same model reading the pasted history, it is 22.40 points ahead. The full table, the rule that decides who is in it, and the caveat each figure carries are in docs/RESULTS.md; the figures themselves are recorded as data with their sources in tools/references.json.

The engine routes a question to one of four reading strategies (lookup, tally, timeline, advice) with a regex classifier over the question text. Whether that is tailored to the benchmark is a fair question with a checkable answer: the classifier reads the question text only, has no access to the dataset, and no caller can override it. Print it from the shipped source and measure it yourself:

node tools/verify_router.mjs /path/to/longmemeval_s.json

What that measurement can and cannot rule out.

One memory layer, five answering models

The store is portable across models; the score is not. So the same 500 questions were answered again with everything held fixed (same stores, same rendered prompts, same regex routing, same judge) and only the answering model swapped:

actoraccuracycorrect+/- 1 s.e.task-averaged
Claude Fable 592.00%460/5001.2191.94%
Claude Opus 591.00%455/5001.2890.94%
Claude Sonnet 585.60%428/5001.5786.75%
openai:gpt-4o (release run)83.00%415/5001.6884.02%
Claude Haiku 4.578.00%390/5001.8577.66%
openai:gpt-4o, no memory system60.60%303/5002.19not published

The last row is the same model with no memory layer at all: the benchmark authors' own full-context baseline, where the entire history is pasted into the context window and the model answers from that. It is their measurement on their harness, not a run of ours. Its count and standard error are arithmetic on that published percentage at n = 500, by the same formula that gives every other row its s.e.; the task-averaged column is left open because it needs the six per-type accuracies and they published one overall figure. Read against our gpt-4o row it is the cleanest comparison available, because the actor is identical and the only variable is the memory: 83.00% against 60.60%, a gap of 22.40 points, and it is the row that costs the most to run, since pasting the history is what a 100,000-token prompt per question means.

Fable 5 and Opus 5 are inside one standard error of each other and should be read as tied. The whole spread sits in multi-session synthesis (88.72% down to 69.92%); retrieval was identical for every row, proved by a byte-identical per-question diagnostics file. The Claude rows were produced through the manual provider route rather than the API, which is a real difference and is disclosed in full in RESULTS-ACTORS.md.

Retrieval, measured on its own

A retrieval-only sweep re-reads the same 500 questions at k = 1 to 15 with no model call at all: content recall is 96% at k=1 and 98% from k=3 onward, and nothing above k=5 moves it. The shipped operating point (k=5, 10,065 tokens) is where the curve is already flat. Multi-session sits at 99% content recall and 72.18% accuracy with gpt-4o, which is the clearest evidence that the remaining errors are reading errors, not search errors.

Recall at k on LongMemEval-S

Full tables, both recall definitions, and the zero-network-call proof are in experiments/recall-sweep/.


When it earns its place, and when it does not

Below roughly 20k tokens of history there is not much to save. You are asking a few questions and the whole conversation still fits in the window, so the raw text is what gets used and DaiDocs is not doing much for you. Past that point the history stops fitting, and the .dai store is what keeps the answers available. The background conversion runs either way, every 4,000 tokens, so by the time you cross that line the store is already there.

Agent traces are the one shape it does not handle well. Tool calls, stack traces and file dumps look nothing like conversation, and converting them today produces poor stores. That is a real gap and it is being worked on.

Want it run for you? The engine here is the whole engine and always will be, self-hosted and free under Apache-2.0. If you would rather not operate it, we host it: conversion, storage and recall as a managed service, same format, same files, exportable at any time. That is how the work here gets funded. See daidocs.com.


Choosing your model

Setup asks you once, at install, and that choice then applies everywhere. Conversion, the hooks, the MCP server and the CLI all use it until you change it.

On a Claude subscription, in Claude Code: use Opus. It is what we recommend, and on a subscription the conversion is written by the assistant already in the conversation, so there is no API key and nothing extra to pay.

With an API key: use openai:gpt-4.1-mini. Low cost, high accuracy, and it is the observer every published number in this repository was measured with. gemini:gemini-3.1-pro is the other good choice.

Conversion is cheap in tokens. Converting a session costs roughly what the session already occupies plus a question or two at that same size. It is not a second pass over your whole history; it reads what is new, once.

Go higher if you like, but do not go lower. The observer's output is baked into the file permanently, so every future answer is limited by what it captured the first time. A model that captures 65% of what mattered instead of 96% does not give you slightly worse recall later: it gives you a store that no longer contains the answer. The five-model comparison above is the measured version of that: the same store, the same questions, and a 14-point spread purely from who is reading.

The answering model is the cheap decision and can change per question. The observer is the one worth spending on, because you only get to run it once.


Using it

Six tools over MCP: save_memory, recall_memory, list_memories, read_memory, declare_project and brief_parent. You never call them; you ask naturally:

  • "save this chat to memory"
  • "what did we decide about the deploy pipeline?"

With the Claude Code hooks installed, every session saves itself as you work, with nothing to remember.

Reading a store efficiently is a separate step from connecting one, and it is the step people skip. Loading whole .dai files instead of the three zooms costs an order of magnitude more tokens for no accuracy gain. setup.js installs the protocol into ~/.claude/CLAUDE.md for you; the same rules are in prompts/READER-PROMPT.txt to paste into any assistant.

node daidocs.js ingest ./my-chats ./my-store    # convert a folder
npm run check                                    # verify an install, no API key needed
variabledefaultwhat it does
DAIDOCS_STORE~/DaiDocswhere the store lives
DAIDOCS_OBSERVERthe model you chose at installoverrides that choice for one run
DAIDOCS_DISABLEunsetskip the auto-archive hook
DAIDOCS_NO_PINGunsetrefuse the one-time opt-in install ping without being asked

Reproduce our numbers

You reproduce the number by running it, not by downloading our answer file. Three things, all public: the dataset (LongMemEval-S), the engine (lib/methods/daidocs-v44n, in this repo), and the scorer (the benchmark authors' own evaluate_qa.py). Protocol in docs/REPLICATION.md.

Per-question outcomes are in benchmark/ so you can find which questions differ rather than comparing two totals. If you cannot reproduce a number, that is the most valuable issue you can open, and we will say so publicly rather than quietly editing the page.


Repo map

pathwhat it is
QUICKSTART.mdfive minutes, nothing assumed
spec/DAIDOCS-STANDARD.mdthe .dai format specification
docs/RESULTS.mdthe conditions, the disclosures, and every number once measured
docs/REPLICATION.mdhow to reproduce them
docs/READ-DAIDOCS.mdthe reading protocol, per surface
docs/INTEGRATION.mdusing it with Claude Code: hooks, converting history, keyless saving
prompts/the protocol as a paste-anywhere prompt
daidocs.jsthe CLI: convert, pending, stores, backup, scrub, ingest, ask
setup.jsone-command install and configuration
lib/methods/daidocs-v44n/the engine, in the configuration this repo ships
mcp_server.mjsthe MCP server
session_archiver.mjsthe Claude Code SessionEnd hook
session_context.mjsthe SessionStart hook: memory loads at the start of a session
session_autosave.mjsthe Stop hook: sessions save themselves, with no API key
verify_surfaces.mjsnpm run verify: every surface, free and offline
keyless_check.mjsproves nothing needs an API key to run
lock.jsnpm run lock: makes this folder read-only
assets/the brand marks, the charts, the diagrams and the demo
benchmark/run_longmemeval.mjsthe benchmark adapter, so the run is checkable
benchmark/per-question results
RESULTS-SUMMARY.mdthe release run, gpt-4o, in one page
RESULTS-ACTORS.mdfive answering models over the identical memory layer
run-artifacts/answers, judge verdicts, diagnostics and the run manifest, per actor
experiments/recall-sweep/recall@k, k = 1 to 15, retrieval only, zero API calls
MANIFEST.sha256sha256 of every file as frozen; docs/PROVENANCE.md says how to verify
docs/GAPS.mdthe honest list of what has not been done
tools/verify_router.mjsprints the router from source and measures it
tools/check_numbers.mjsfails CI if any published number drifts from the artifacts
tools/make_charts.pyregenerates the charts from the numbers
tools/chart_theme.pythe daidocs.com chart surface, ported to matplotlib
tools/make_diagrams.pyregenerates the explainer diagrams
tools/dashboard/npm run dashboard: builds the memory map. A built page is never shipped
docs/GUIDE.mdevery command, tool, script and folder type, in one page
tools/make_badges.pythe badges at the top, as local files rather than fetched
CHANGELOG.mdwhat changed, per release
SECURITY.mdhow to report something, and what is in scope
RUNBOOK.mdthe release run, step by step

Contributing

The format is the point, so the most useful contributions are the ones that put it in more places.

Integrations. A store that only one assistant can read is not a format, it is a database with extra steps. The MCP server covers Claude Desktop, Claude Code, Cursor and Windsurf. Everything else is open: an extension for another editor, a plugin for another agent framework, a loader for another runtime, an adapter for an assistant that speaks something other than MCP. If you are wiring one up and something in the format fights you, that is a bug in the format and worth an issue. Two we want by name: an OpenRouter provider backend, one key and hundreds of models, which turns bring-your-own-model into a line of config and slots into lib/providers/ beside anthropic, openai and gemini with the same small contract; and a Hermes agent integration, so someone running that stack can point it at a store and have memory work.

A second implementation. A reader or writer that is not this code. It is deliberately small enough to write in an afternoon: UTF-8, a YAML header, a JSON zone and text. Two independent implementations is the difference between a file layout and a format.

Improvements to the memory itself. Better extraction, better retrieval, better handling of the shapes that do not work yet. Agent traces are the obvious one: tool calls and stack traces convert badly today and somebody solving that would be solving it for everyone. Anything that makes recall more accurate, or makes a store cheaper to read, is welcome.

Bugs and rough edges. Especially on macOS and Linux, which are audited but much less used than Windows here. If something is confusing rather than broken, that is still worth reporting: a feature nobody can find is a feature that does not exist.

Small changes are welcome without asking first. For anything that changes the format itself, open an issue before writing code, because that is the part other people's work depends on staying still.

By contributing you agree your work is licensed under Apache-2.0, and you sign off that you have the right to submit it (DCO).


Counting installs, opt-in and off by default

DaiDocs is local-first, and the tool sends nothing on its own. There is exactly one exception, a single install ping, and it is built to keep that promise rather than bend it:

  • It is asked once, on the first interactive setup, and never again.
  • The default is no: a bare Enter declines, and it never prompts on a non-interactive run.
  • A yes sends one anonymous request: a random id, the version and a timestamp. Nothing that identifies you, your files or your memory.
  • DAIDOCS_NO_PING=1 refuses it outright, without being asked.
  • The choice is recorded in ~/.daidocs/install.json; delete that file to be asked again.

It exists so the project can count how many people install it. If you would rather it did not exist at all, that one variable turns it off for good.


Licence

The specification, the engine and the MCP server are Apache-2.0, including a patent grant. Commercial use, modification and redistribution are all fine. There is no lagging free edition: what is published here is what runs.

Built by Kerneta.

Languages

JavaScript

80.9%

HTML

10.2%

Python

8.9%