Sign in #
Two ways in. A person uses the device flow, which prints a code that somebody with admin on that server approves. --token stores a credential you already hold, such as the one signup shows once. There is no command yet for an admin to issue a separate token for CI; sign the CI machine in once with the device flow as the person it acts for.
$ ns-brain hive login --server https://hive.example.com $ ns-brain hive login --server https://hive.example.com --token hive_... # from an account that can approve $ ns-brain hive approve WXYZ-1234 --email them@example.com --node 4 --role contributor
Run it inside a project and, once the credential is stored, login offers to attach that project. It says what will happen first: how many memories, open tasks and log entries a local brain would copy up (a dump is written first and the local copy stays), and which files in .claude/ get the hooks. It then asks Attach now? [y/N]. Anything but yes attaches nothing and sends nothing, and it prints the command to run later. With nobody there to answer, as with an agent, CI or a pipe, it does not attach. --attach is that yes given up front. A project already on another server is never re-pointed, because that would leave its memories behind; login prints the leave/join pair that moves it. Without --server, login and logout use the project's own server, then https://hive.fightclub.pro, and say which one they picked.
There is no identity provider behind the device flow yet. A named admin approves each sign-in, which works and is auditable and Google or GitHub is a swap behind the same flow rather than a redesign. Said here rather than left to be discovered.
The first approval on a new server comes from somebody with shell access and everybody after that from a human admin through the API. That order exists because the owner created by --init-org once held a credential that could not let anybody else in, which meant the product had no route from one person to two.
Where the credential lives
Outside every project, in your OS config directory as ns-brain/credentials.json, mode 600. That location is not a detail: a token inside a project is one git add from being published. The client refuses to read the file at all if it is group or world readable and tells you to chmod it rather than carrying on. NS_BRAIN_CREDENTIALS moves it.
One machine can hold credentials for several brains and they never mix: the key is the server and the organisation, because one server can host two companies you belong to. A project names its organisation in brain.json (hive join writes it) and a project that names a server holding several of your brains and no organisation is refused with the list, never guessed. ns-brain hive status shows every brain this machine holds and hive logout --org <name> --revoke signs one of them out for good.
$ ns-brain hive status # is the server there, who am I, what is queued $ ns-brain hive nodes # the part of the tree this credential can reach
Get a machine onto the brain #
A machine joins in one command and its private key never leaves it. Only a certificate request goes to the server; the key is generated where it will be used.
$ ns-brain axon enrol --email you@example.com --relay relay.example.com:7800
It asks for your password, never takes it on the command line. An email the server has not seen registers a new brain and generates an opaque id for it; one it knows adds this machine to the brain you already have.
A machine enrolled that way is temporary. A password works from a machine you will never see again, so what it buys is a device that expires on its own, thirty days later, whatever its certificate says. For a machine you keep, approve it from one you already hold:
$ ns-brain axon enrol --relay relay.example.com:7800 # on the new machine; prints a code
$ ns-brain hive approve-machine WXYZ-1234 # on a machine already on the brain
The code admits nobody by itself. It names a request that is waiting and the authority is the credential of whoever approves it, which is why it can be short enough to read down a phone.
The password only ever enrols. It is never accepted for reading or writing a memory, so somebody who phishes it can add a machine and nothing else and that machine is visible in ns-brain hive machines and revocable.
$ ns-brain hive machines # what is enrolled
$ ns-brain hive pending # what is waiting to be approved
$ ns-brain hive password # set the password that enrols a new machine
$ ns-brain axon status # this machine's name, relay and expiry
$ ns-brain axon renew # a fresh certificate before this one expires
$ ns-brain hive logout --server <url> --machine ci-box # revoke there, forget here
Revoking a machine that is not the one you are sitting at leaves the one you are sitting at signed in, because logging out a laptop you no longer hold is done from a machine you still do. The revoked machine is refused at the relay within a minute and any session it is holding is dropped straight away. Its name is then retired for good: admission is by name and the certificate it holds stays valid until it expires, so letting the name come back would let the certificate come back with it.
Certificates last ninety days on a machine that may renew and renewal is not automatic until you put axon renew on a timer. Do that on the relay first. Every machine checks the relay by name before it will talk to it, so the day the relay's certificate expires is the day nothing reaches the brain from anywhere.
Machines that are not on the same network #
The whole of that story is on its own page: what it costs in latency, what the relay can and cannot see and what happens the day a machine is stolen.
A brain at home and a laptop in a cafe cannot reach each other. Neither has a public address and neither should. Axon is the way across: every machine dials out to a relay you run and the relay splices two outbound connections together without ever terminating the TLS inside them. No inbound port anywhere, no VPN, no TUN device and whoever runs the relay sees ciphertext.
$ ns-brain axon init --dir ~/axon-ca --org $(openssl rand -hex 8) # your own authority
$ ns-brain axon issue --dir ~/axon-ca --machine relay # the relay's identity
# on the box that will be the relay
$ ns-brain axon install --from ./relay --relay 127.0.0.1:7800
$ ns-brain axon relay --addr 0.0.0.0:7800 --dir /etc/axon \
--admit /etc/axon/admit --hive <the machine holding the brain> --enrol
Machines are named <machine>.<org>.axon.internal and a client verifies the name it asked for, not merely a chain that validates. Every machine in one org holds a certificate from the same authority, so a chain always verifies; checking the chain and stopping there would let a hostile relay splice you to a different machine in your own org. The names are never resolved in DNS, so there is nothing to publish and no list of your machines to leak.
The relay admits machines from a list that is a projection of the brain's own register, pushed on every change and again every minute. Two registers would mean somebody revokes one and forgets the other and the failure would be silent in the direction that hurts.
Move a project onto it #
$ cd ~/projects/yours $ ns-brain hive join # dry run $ ns-brain hive join --apply $ ns-brain hive leave --apply # back to a local brain
Dry run by default, per project, the same shape as share. It writes the server and the node into the project's brain.json under "hive" and from then on the ordinary commands go to the server: recall, remember, brief and the session hooks you already wired.
An attached project never falls back to the local file. If the server cannot be reached for a read, you get an error naming the server, not a confident answer out of an empty database nobody has written to in a month.
Because the URL comes out of brain.json, which is committed, the client refuses to send a bearer token to anything that is not https or loopback.
Add another project on a machine already signed in #
The credential belongs to the machine, so a second project needs no second login and no approval. In the new project's root:
$ ns-brain init --hive https://hive.example.com # no brain yet $ ns-brain hive join --apply # a local brain: copied up first
Both find the node themselves: the project's own if the organisation already has one by that name, else the organisation's, under which the server files the project on its first write. Starting a new project therefore needs contributor on the organisation. Somebody granted on a single project is refused with that reason and nothing is left behind; an admin fixes it by approving a fresh login from them at the organisation. Every hive server serves the complete reference at /docs, click here to see the one on hive.fightclub.pro.
What happens when the server is not there #
$ ns-brain hive queue # what is waiting, and what the server refused $ ns-brain hive flush # send it now
Writes queue locally, in order, per device and go in on the next command that reaches the server. Reads do not queue, because there is nothing to queue: a read either has an answer or it does not.
Refusals are kept in the queue rather than dropped. A write the server rejected is information about your data and discarding it to keep the queue tidy would lose the one copy you have.
The HTTP API #
The server speaks HTTP and JSON under /v1: recall, remember, brief, nodes, whoami, export, doctor and the admin routes for retention, legal hold and settings. Bearer token in the Authorization header, the same one hive login stored.
/v1/health is open and reports what the server actually has, including whether an embedding model is loaded, rather than a boolean nobody can interpret.
Every route the server serves is documented, with the credential each one takes. There is no MCP endpoint on a Hive server yet. MCP is served by ns-brain on your own machine, over stdio or your own HTTP listener and that page covers it. An OAuth endpoint on the hosted server, so a client can attach with nothing installed locally, is planned and not built.
Version floors #
The client sends its version and the server refuses anything below its floor, with the install command in the refusal. A server supports clients back to that floor and not forever.
$ ns-brain version $ curl -s https://hive.example.com/v1/health
Nothing upgrades itself. Back up first and verify on your own data afterwards: counts unchanged, doctor clean and a recall whose answer you already know still returning it. An upgrade that reports success is not the same as an upgrade that worked.
Running your own #
The server is one binary over Postgres. Each organisation's data key is wrapped by a master key held on the server, which means that key is the entire safety net: lose it and the memories cannot be read by anyone, including you. Copy it off the machine before the server holds anything real and treat backups as restore-tested rather than merely scheduled.
Inside your own perimeter with your own key custody, packaged as an image with a signed licence, is the appliance. Hosted by us is Hive. Same code either way.
The operator surface
ns-brain hive serve --help lists all of it. The ones that decide what the server is:
| --dsn --master-key | Postgres and the file holding the key every organisation's data key is wrapped with. Both required. |
| --addr | What to listen on. Put TLS in front of it. |
| --signup | Let strangers create an organisation. Off by default, rate limited in the store when on. |
| --licence | An appliance licence file. It is verified before the shell subcommands run, not after, so the seat cap applies to those too. |
| --axon --axon-dir | Serve over axon as well as HTTP, with this machine’s identity and its admission list in that directory. The directory has to be readable by the user the unit runs as. |
| --embed-url --embed-model --embed-dims --embed-every | Turn on semantic search: where the embedder is, which model, how wide its vectors are and how often to sweep. Without them the search is lexical, which is what the free edition does and is never worse than it — semantic ranking adds candidates and reorders, it never removes a lexical hit. |
And the one-shots, which do their job and exit rather than serving. --init-org with --init-owner creates the first organisation and its owner. --approve with --approve-email, --approve-node and --approve-role lets the first person in from a shell, which is where the route from one person to two starts. --adopt-axon with --adopt-org installs an authority generated by hand, taking the issuing half only — the ordinary position is that the root belongs offline. --adopt-axon-root is the exception and exists for one case: an organisation whose authority was generated before the root key was kept cannot sign a successor to its own issuing CA, so on the day that certificate expires every machine stops at once. Giving the server the root key makes it rotatable, at the cost of root and issuing sitting behind the same master key. --adopt-machine puts a name into the admission register directly. --credit posts to an organisation’s balance.