The rule from March, found in November.
Groundnote is a self-hosted MCP server. It keeps the rules from your meetings and mail with quote, source and date, so your assistant can find them again.
A real search against a local instance with invented data, formatted by examples/demo/hit.jq.
Why
March, workshop meeting. Mara says:
“matte black frames need two extra days in the oven.”
November, a customer writes:
“Could you paint my frame in RAL 9005 by Friday?”
Nobody remembers the meeting, let alone that RAL 9005 is the paint the workshop calls matte black.
Groundnote keeps that sentence as a rule, together with the meeting it came from and the minute it was said. A person confirms it once. When the mail comes in, the assistant asks Groundnote and gets the rule back with its quote and date. Once nobody has confirmed or reviewed a rule for 180 days (configurable), the answer asks whether it is still valid.
Groundnote decides nothing and answers nobody on your behalf. It tells you what was said, by whom and when.
How it works
Capture
A meeting transcript or a mail is posted to
POST /v1/sourcesand stored as it arrived. Feeders that do this on their own are not built yet, so for now your own script calls the API.Propose
An assistant reads it and calls
propose_rulewith a statement and a quote. The quote has to be in the stored source, otherwise the proposal is refused. A manual proposal, typed in without a stored source, has nothing to check against, and the approval page marks it as unchecked.Approve
Each scope sets a mode. In C, the default without an
approvalblock, every proposal waits for a person. In A and B deterministic code adopts what it may, never a model. Payment data, contradictions, injection signals and the other mandatory exceptions wait for a person in every mode.Answer
search_rulesreturns the rule with its quote and source, earlier and later versions, contradicting and related rules, and where it sits in your structure.
Rules are never edited in place. A change is a new version, and the old one points to its successor.
Search in three stages
- a
- Runs on your machine and is always on. It handles spelling, word forms, German compound words, typos and your synonym list, which is how “RAL 9005” finds “matte black”.
- b
- Embeds rules and queries with a local ONNX model, fetched once with
groundnote model fetch, and fuses its ranks with stage a. Nothing leaves your machine. Off by default. - c
- Sends the best candidates to TypeSafe AI's JEV reranker in the USA, which re-orders them within a monthly cap. Off by default.
Every response lists each stage as ran, off, failed, budget or not-allowed, so you can tell when a stage did not run.
What the measurements say
Stage a against plain full-text search, on a held-out synthetic set: 300 invented rules and 137 queries that were written after tuning and never used for it. Source: lexical report.
The last two rows got worse, which is the price of the extra variants. The search documentation shows every set and what each step adds.
| Plain full-text | Stage a, defaults | |
|---|---|---|
| Relevant rules in the top ten (recall@10) | 67% | 75% |
| Rank of the first relevant hit (MRR, 1.0 = always first) | 0.66 | 0.80 |
| Outdated version ranked above the current rule | 86% | 7% |
| Questions without an answer that still get a confident hit worse | 17% | 25% |
| Search time, 95th percentile worse | 1.2 ms | 1.7 ms |
Stages b and c on a synthetic set of 300 rules and 180 queries, with bge-m3, through the real search. Source: semantic report.
On this set stage b helps most with paraphrases (recall@5 30% to 54%) and with questions asked in the other language, German or English (48% to 85%). Only stage c filters questions without an answer.
Not everything improves. Each stage adds search time, and stage c pushes some categories down: recall@5 falls from 86% to 80% for queries with codes and from 95% to 91% for direct ones. With the model loaded the measuring process used 6.6 GB of memory. The JEV calls of the whole run cost 0.06 USD.
| a | a + b | a + b + c | |
|---|---|---|---|
| Relevant rules in the top five (recall@5) | 73% | 84% | 90% |
| Rank of the first relevant hit (MRR) | 0.83 | 0.89 | 0.98 |
| Questions without an answer that still get a hit | 16 of 16 | 16 of 16 | 5 of 16 |
| Search time, median / 95th percentile | 5 / 8 ms | 25 / 114 ms | 241 / 309 ms |
Data model
Each scope (a team, a customer area, a project) is its own SQLite file, with no joins across files. Searching several scopes has to be asked for and is only allowed when the grant covers all of them.
Inside a scope, entities such as customers, projects, topics and people form one tree of any depth, and links tie them to rules and sources. More in the knowledge graph documentation.
Security and privacy
- Text from mails and transcripts is treated as untrusted. It can only become a proposal, and quotes and names leave the server inside marked blocks.
- None of the 15 MCP tools can confirm anything. In modes A and B only code can adopt a proposal, and the mandatory exceptions still wait for a person.
- Secrets come only from the environment, and the server refuses to start when the data directory is readable by others.
Read the threat model and the data flow to the provider before you switch stage c on. Report vulnerabilities privately as described in SECURITY.md.
Quickstart
There is no published image before the first release, so you build it from the repository. This runs in dev-token mode, which is meant for your own machine only. Never publish the port on a public interface in this mode.
Build the image
git clone https://github.com/groundnote/groundnote.git && cd groundnote docker build -t groundnote .Start it
Write a
groundnote.jsonwith one scope and start the container in dev-token mode, published on127.0.0.1only.Create the scope and grant yourself access
Without the grant every MCP call answers
unauthorized.Connect Claude Code
claude mcp add --transport http groundnote http://127.0.0.1:8794/mcp \ --header "Authorization: Bearer $GN_MCP_TOKEN"
Steps 2 and 3 take a config file and more than a dozen flags, so they stay in one place: the full quickstart in the README, ready to copy.
Status
Groundnote is early and unreleased, and the API may still change.
Built
- Search stages a, b (local embeddings) and c (JEV reranker with a monthly cap)
- Approval page with approval modes A, B and C for rules
- Knowledge graph with its review page
- MCP server with 15 tools and 5 prompts
- HTTP API and Markdown export
- The
groundnoteCLI as a thin API client, withdoctor - Backup runs, restore probes and
backup nightlyfor an OS timer, plusbackup verifyandrestore --to
Not built yet
- API providers for stage b
- Adopting structure changes in modes A and B; structure always waits for a person today
- Feeders for meetings and mail
- Litestream supervision by the service
- Redaction and encrypted backups
What comes next is in the architecture document, proposals measured on real data are in the roadmap, and changes in the changelog.