Why not zero-knowledge #
An earlier version of this site said the hosted brain was shaped so the server could not read what it stored. That was the intention when it was written and it does not survive contact with what the hosted product has to do.
Search is the obvious one. Retrieval runs full-text matching and then a ranking pass over the results and neither works on ciphertext. Nor does a web UI that shows you a memory, the conflict queue when two people correct the same fact, or a support engineer looking at why your recall returned nothing. Encrypting so we cannot read it means giving up most of what you are paying for.
So we made the other choice and we are telling you which one it was. What stops an engineer reading your memories is key custody, no standing production access and a break-glass path that is logged, reviewed and rare. That is access control, not mathematics.
If you want an arrangement where we genuinely cannot read your data, there are two and both are real. Mind is free, self-hosted and involves no server of ours at any point. The appliance runs the same team edition inside your perimeter, where the master key is generated on your machine and we never hold it.
How the encryption actually works #
- A data key per organisation. Memories, bodies, titles, events and the activity log are encrypted with it before they touch disk. AES-256-GCM, a random nonce per value, no compression before encryption. Your key never protects anyone else's rows, so two customers never share an encryption boundary the way they might share a database.
- The data key is wrapped by a master key in HashiCorp Vault, which is the only place the master key exists. The database holds wrapped keys; Vault holds what unwraps them.
- Rotation on a schedule and on demand. Rotating the master key re-wraps every data key without touching a memory, which takes seconds rather than a maintenance window. Rotating an organisation's data key re-encrypts that organisation's rows and you can ask for it at any time, for any reason, including no reason.
- TLS 1.3 between machines and nothing where it would be theatre. Traffic that crosses a network you do not own is axon traffic and that path pins TLS 1.3 at both ends and refuses to negotiate down. Inside one machine there is nothing to protect: the web UI and the MCP endpoint bind to loopback, where a TLS handshake would encrypt a conversation a process is having with itself. The hive server speaks plain HTTP to the reverse proxy in front of it, which is where its certificate lives and where you already terminate TLS. The guard that matters at the boundary is the client refusing to send a bearer token to a plain-http server at all, because the server URL lives in a file that gets committed.
Your agent, your model, your credentials #
ns-brain does not call a language model. Your coding agent does that with your own account and the brain never sees the key, the prompt or the completion. It stores text and gives it back, ranked.
The one exception is search quality. At company scale, matching on words alone starts missing what somebody meant, so the hosted brain also builds vector embeddings of what you store. Those run on an open model on our own hardware, paid for by us. Your memories are not sent to OpenAI, Anthropic or anyone else to be embedded and there is no third-party model provider anywhere in the path.
Who can reach what #
Permissions live on the tree you define: organisation, department, team, project. A grant is inherited downward and can be revoked at any level. There are no per-memory sharing rules, deliberately, because a permission model you cannot hold in your head is one nobody can audit. If a memory needs different visibility, it belongs at a different level.
Agents and CI get their own tokens, scoped to a node rather than to a person and capped below the level that can retract a guardrail. A compromised token in a build pipeline is not a route to everything your company knows. Revoking one takes effect on the next request and there is no local replica to chase.
Tokens are 32 random bytes, stored as a SHA-256 hash, compared in constant time, with revocation and expiry. Reads are logged as well as writes, so when a security review asks which agent read what and when, that is a query rather than an apology.
What the last audit found #
The first code-level audit of the server, the MCP transports, the web UI and the client ran on 2026-08-12. An earlier pass had reviewed the specification and found nothing, because none of this is visible in a specification.
The tenant boundary was the whole story. Four issues, all cross-organisation, all in the layer whose comments asserted the opposite:
- A brief request with any node id returned that node's name and full ancestor path, unscoped. Memories were filtered; the node names were not. Any credential in any organisation could have walked ids and read every tenant's tree. It now fails closed with a 403 and the refusal names nothing.
- Retention and erasure ran without an organisation filter, so an owner running their own retention would have deleted expired memories in every tenant. Unreachable over HTTP by accident rather than by design, which is worse. Both take an organisation id now and so do legal holds.
- An organisation's data key was generated with an unconditional update, so two concurrent first requests could overwrite one another and make already-encrypted rows permanently unreadable. Conditional now and the loser re-reads the winner's key.
- The API had no request body limit at all on the two unauthenticated device-flow routes. 8MB now. MCP had 16MB from the start and the UI has 64KB.
Since 2026-09-18 the boundary is also driven from outside, as a company would hit it: tools/hive_company_test.py puts two organisations on one server and, from a credential in one, tries the other's memories by search and by id, its history and restore, notes and broadcasts to its projects, its index, axioms and lessons, a hold on its node, an erasure of its person, its settings, an approval into its root and a revocation of its credential from the dashboard. Every one refuses and the refusals for ids do not confirm the id exists. One person belonging to both organisations from one machine keeps them apart by naming the organisation in each project.
Both cross-tenant failures were reproduced with tests before being fixed and those tests are in the suite. The list of what was not fixed and why each is a decision rather than an oversight, is kept with the audit: no AAD on the encrypted values, the device token sitting in cleartext between approval and first poll, no rate limiting, raw error text to authenticated callers and missing read and write timeouts on the HTTP servers.
We publish this because a security page that only lists what went right is a marketing page.
Backups and getting your data out #
Backups are continuous, encrypted with the same key hierarchy and kept on a rolling 30-day window. Restores are tested rather than assumed and point-in-time restore is self-serve.
Export is complete, free and always available. One JSON file with every memory, every event, the supersession links and the provenance. ns-brain import reads it back into a free local brain that behaves identically, because it is the same binary. Nothing about paying makes your data harder to take somewhere else and nothing about leaving triggers a negotiation.
If an account lapses and stays lapsed, we switch the brain off and hand over the extract. We will not hold a company's institutional memory hostage over a failed card.
Deleting things, properly #
This system is built not to forget. Retractions outrank facts, corrections stay linked to what they corrected and a deliberate deletion leaves a tombstone so the same wrong answer is not learned twice. All of that works against erasure, which is why erasure is built in rather than bolted on.
What is captured about the person
The session hook stores every user message verbatim before the turn is answered, clipped at 8000 characters and classified. There is no per-message opt-out: the only way to turn it off is not to wire that hook, with ns-brain init --no-auto-recall, which also turns off automatic retrieval. Credential-shaped text is refused outright with no override, because no human is on the other end of a hook to ask.
That text is in the store like anything else, so it comes out in export, backup and snapshot, in cleartext and it travels with the brain when the brain moves. On a shared brain, tell the people whose messages it is.
When a person asks to be forgotten, we remove what they wrote and their attribution across memories, tombstones, events and the search index, then let it age out of backups inside the 30-day window. We do not claim to scrub every mention of somebody from text other people wrote about an incident. That promise is unbounded and a promise nobody can keep is worse than a limit written down.
Per-node retention is yours to set. Finance can keep things for years while another team deletes on a timer and a parent can lock a setting so a team below cannot loosen it.
Where it runs #
EU by default, on servers in Germany and Finland. That is where the company is and where most of the first customers are, so residency is the starting position rather than an upgrade you buy.
A standard DPA is included on every paid account, from the cheapest tier upward. Under GDPR that is table stakes for anyone with European customers and holding it back for an enterprise tier would just mean nobody in Europe can legally buy the cheap one. The subprocessor list is short, published and changes with notice.
What the free edition does and does not #
Mind writes a SQLite file in your project at mode 600, adds it to .gitignore and refuses to store text that looks like a credential unless you override it. The one network call it makes on its own is a daily GET of brain.fightclub.pro/latest-version.txt at session start, to say when an upgrade is out. It sends nothing but the request, a failure is silent and NS_BRAIN_NO_UPDATE_CHECK=1 turns it off. No memory ever leaves the machine.
There is no encryption at rest and that is deliberate. A lone developer has no second party to be protected from and an unnecessary key hierarchy is an excellent way to lose a brain permanently. Full-disk encryption on your laptop is the right layer for that job.
Two more things worth knowing if you run it: several projects can share one database file, in which case the project filter is a filter and not a boundary and --all-projects widens on purpose. A project can opt out of being read that way with ns-brain private. Anything that needs a real boundary gets its own file, which is still the default. The details are here.
The moment a colleague's reasoning is in the store, the argument changes and that is where the hosted key hierarchy starts.
Reporting something #
Mail security@brain.fightclub.pro. We answer within one working day, we will not threaten you and we will credit you unless you would rather we did not.