Team hub
A team keeps its notes where it always did, in each person’s store. A hub is the one machine that collects the audit trail: which machine did what kind of thing, and when, in chains that cannot be edited afterwards without it showing. A row says that a note was written, never what it said.
A hub is a separate surface, not serve opened to the network. It authenticates, and what it can do is short: take audit rows and, where a store switched it on and two people agreed to a bereich, hold and hand back the notes of that bereich. It cannot read, write, delete or apply retention on anybody’s store.
This page condenses docs/HUB.md, which has the full picture. Commands and flags here are checked against 0.8.4.
The licence
A hub needs one; without it nothing is registered and nothing collected. It is a signed file checked against a key built into the binary. There is no call home.
$ cyberbrain hub licence install licence.txt --data /var/lib/cyberbrain/hub.db
$ cyberbrain hub licence show --data /var/lib/cyberbrain/hub.db
licence show exits non-zero when the hub is not collecting, so a monitoring check is one line. A licence file dropped beside the record (licence.txt) is picked up at start.
Seats are machines. Every project is its own store and so its own device on the hub, but devices that report the same machine share one seat. A second project on a machine that already has a seat can be registered on a full licence by naming the machine: hub add ws-021-dispo --machine ws-021.
When it expires the hub stops accepting rows and does nothing else. The record stays readable, devices keep working, clients buffer, and a renewed licence takes what they held without a gap in the chain.
Running one
On Linux:
$ cyberbrain hub add "laptop-anna" --data /var/lib/cyberbrain/hub.db
$ cyberbrain hub serve --addr 0.0.0.0:7788 --data /var/lib/cyberbrain/hub.db --tls-generate
hub add prints the device token once and stores only a hash. --invite <file> --hub-url <url> writes an invitation file instead, which carries everything the machine needs (optionally the shared inference address with --inference-url). Hand it over like a password. hub serve defaults to 127.0.0.1:7788; a hub only its own machine can reach collects nothing, so give it an address the network reaches. HUB.md has a systemd unit.
On Windows, tick Hub service (collector) in the installer, or run cyberbrain-setup.exe /S /HUB. That registers the service Cyberbrain Hub on 0.0.0.0:7788, opens the port in Windows Firewall, makes the hub its own certificate and creates C:\ProgramData\Cyberbrain. Licensing it is copying licence.txt there and restarting the service. The same by hand:
> cyberbrain hub service install --data C:\ProgramData\Cyberbrain\hub.db
> cyberbrain hub service status
hub service uninstall, and removing the program, leave the record alone.
Many machines at once
A fleet invitation enrols many projects with one file:
$ cyberbrain hub invite create --uses 60 --expires P14D --label "Rollout Disposition" \
--hub-url https://hub.example.internal:7788 --out rollout.json --data /var/lib/cyberbrain/hub.db
Each project that runs cyberbrain hub enrol rollout.json (or Connect to the company hub… in the Windows launcher) gets a device of its own. --expires is at most 90 days; hub invite list and hub invite revoke manage them. An address that tries ten unknown codes within ten minutes is turned away with 429 for the rest of those minutes. Behind a reverse proxy every machine has the proxy’s address, so one guesser there locks out everybody for that time. The company rollout is in docs/ROLLOUT.md.
Encryption
Without a certificate authority of your own, --tls-generate makes a certificate once and keeps it beside the record. Every invitation issued afterwards carries its fingerprint, and enrolled machines pin it: they accept that certificate and nothing else, and refuse plain http. Browsers do not know it and warn; hub cert show prints the fingerprint and the commands to put it into a machine’s trust store, hub cert export <file> copies the certificate (never the key) for a share or a group policy.
With a certificate of your own, give --tls-cert and --tls-key in PEM. Such a certificate is never pinned; clients verify it against the machine’s trust store, so a renewal does not stop them.
Without any certificate the hub still collects, warns at every start and shows a banner. The administrator password can then only be typed at the hub’s own machine.
The hub’s page and signing in
The hub’s page is at http://localhost:7788/ on its own machine: licence, seats, devices, people with a role, fleet invitations. It is rendered on the server and has no JavaScript.
There is no default password. The account is admin, and the first visit from the machine the hub runs on sets the password. After that the page opens from any desk, provided the hub is encrypted. hub admin reset --data … forgets the password, and the next visit from the hub’s own machine sets a new one. A wrong password costs a fixed delay rather than a lockout, and every refused sign-in is in the hub’s own log.
“From the machine the hub runs on” means a loopback connection whose Host header also names loopback. That keeps a DNS-rebinding page from claiming an unclaimed hub.
Open point in 0.9.1: a reverse proxy and the first sign-in. A reverse proxy on the hub’s own machine connects from loopback, and depending on the
Hostit forwards, the first-visit rule above can misjudge whether a request comes from the machine. How the hub should treat that case is not settled yet. Until it is, set the administrator password directly at the machine, athttp://localhost:7788/and not through the proxy, before you put a proxy in front, and let the proxy pass the originalHost. With nginx that isproxy_set_header Host $host;: its default sends the upstream address,127.0.0.1:7788, which looks like the machine itself.
Delivering to it
$ cyberbrain hub enrol ws-021.json
$ cyberbrain hub push
hub push sends the store’s audit rows to the hub it was enrolled with. Run it on a timer, once an hour is plenty; the Windows launcher delivers by itself every quarter of an hour. Nothing is buffered separately: the audit log is the buffer, the hub skips what it already has, and a delivery that leaves a gap is refused with 409. Overlap is fine.
The device token is not in the store. It goes into your configuration directory, one file per store and hub, or into CYBERBRAIN_HUB_TOKEN for a service account. Editing the hub URL in cyberbrain.toml does not redirect the audit trail: the egress gate refuses any destination other than the hub this store enrolled with.
hub fleet shows the devices, those with something wrong first: never reported, a refused delivery, quiet for 71 hours, an older version.
Sharing notes
By default the hub holds audit rows and nothing else. A note’s text travels only if all of these hold:
allow_note_sync = true in the store’s [hub] section |
off by default |
the note carries a bereich |
no bereich, no sharing |
| ring 2, 3 or 4 | rings 0 and 1 never leave the machine, whatever is granted |
| a grant for that device and bereich, in the right direction | send, receive or both |
| a second person countersigned the grant | not the one who wrote it |
$ cyberbrain hub grant add --device dev_01J… --bereich disposition --direction both \
--reason "Shift handover within the department"
$ cyberbrain hub grant approve bg_01J… --as <countersigner credential>
Two people, because whoever runs the hub registers devices and can read a device token out of an invitation file. If that person could also point a bereich at a device, every note text on the hub would be one form away from them.
On the machine, cyberbrain hub push --notes sends the notes, and cyberbrain hub pull takes what the hub holds for this machine. pull never overwrites a note changed here since the last pull; it reports it. Erasures are reported and acted on only with --apply-erasures. Two machines that changed the same note produce a conflict, which an editor of that bereich settles with hub conflicts.
cyberbrain hub erase <name> --bereich <b> removes the hub’s copy and leaves a tombstone. It works even with sharing switched off. A local forget does not reach the hub; it says so and names this command.
Who may see what
| Role | Sees | Does not see |
|---|---|---|
admin |
devices, gaps, versions, seats, licence | activity rows |
auditor |
activity, only inside an approved window | anything without a countersignature |
countersigner |
every request with its reason, the access log, grants waiting | rows, unless also an auditor |
editor |
note conflicts in the bereiche assigned to them | anything else |
$ cyberbrain hub principal add "M. Kraus" --role auditor --expires P1Y
$ cyberbrain hub request --device dev_01M1Y9… --reason "Revision query of 5 Sept" --as $AUDITOR
$ cyberbrain hub approve req_01M1YB… --hours 2 --as $COUNCIL
$ cyberbrain hub disclose req_01M1YB… --out-dir case-2026-09 --as $AUDITOR
Credentials are shown once and stored as a hash. Every step is in the hub’s own hash-chained log, hub access-log. Countersigners and administrators are made only at the machine with hub principal add, never from the page.
What this does not do. It enforces the route: through this program, activity is unreachable without a request somebody else approved. It does not stop someone with file access to the hub’s database, who can open it with any SQLite tool. Put the hub on a machine with controlled access, and describe this in a works agreement as a procedure supported by software, not a guarantee made by it.
Keeping it
| Command | |
|---|---|
hub verify |
re-check every chain against the rows on disk now; non-zero on a broken chain |
hub backup <file> |
a restorable copy through SQLite, checked after writing; never overwrites. Do not copy hub.db by hand: the newest rows may still sit in hub.db-wal. |
hub retention set P2Y |
the period; removes nothing by itself |
hub retention propose --reason … / approve <id> |
a purge, written by one person and carried out when a countersigner signs |
hub alerts set <url> |
post what needs a person to one webhook: countersignatures waiting, the licence ending, devices quiet for 48 hours, failing governance calls, used decoys. Loopback or private unless --allow-public |
hub report --out-dir <dir> |
what the fleet did in a period, as state: one line per device with its row count and whether its chain holds. Not the rows; those take request, approve and disclose. |
hub revoke <id> |
stop a device from sending; its rows stay |
Backups keep what a purge later removes. If the retention period is a promise to the people whose activity this is, rotate the backups within the same period.