@network-harness/directory
v0.2.0
Published
Part of the network harness: @network-harness/directory.
Readme
@network-harness/directory
The reference discovery provider's server side: presence, and what each node says it offers. It exists so two nodes that have never met can find each other without either of them running a registry.
It knows nothing about protocols. An advertisement has a kind, a name, and a body the directory never reads, in one table rather than one per kind. The predecessor had three tables -- agents, queries, skills -- which made every new kind of thing to advertise a change to the directory; this one is indifferent, which is what lets a protocol introduce a kind on its own.
Every write is signed, and checked against the id it claims. Three questions in order: does the carried key derive the node id, is the signature that key's, and is the record recent enough to be current. The first is what makes an id unforgeable without any account or password, the third is what stops a captured write from being replayed later. An advertisement can only be withdrawn by the node that placed it.
It holds nothing private. Everything here was published on purpose, and losing the database costs a node one republish tick.
Hosting one
A directory is one process, one sqlite file, and no secrets. Anyone can run one, and a network is whichever nodes point at the same one.
npx @network-harness/directoryIt listens on 127.0.0.1:7460 and writes directory.db in the working
directory. Three environment variables move those:
| variable | default | what it is |
| ------------------------ | -------------- | ------------------------------------------------------- |
| HARNESS_DIRECTORY_HOST | 127.0.0.1 | the interface to bind |
| HARNESS_DIRECTORY_PORT | 7460 | the port |
| HARNESS_DIRECTORY_DB | directory.db | the sqlite file, resolved against the working directory |
The default binding serves only this machine. To serve other people, bind every interface and put a TLS terminator in front of it:
HARNESS_DIRECTORY_HOST=0.0.0.0 HARNESS_DIRECTORY_PORT=7460 \
HARNESS_DIRECTORY_DB=/var/lib/harness/directory.db \
npx @network-harness/directoryServe it over https. Nothing here is private, so plaintext leaks nothing -- but every record a node reads from a directory steers what it does next, and a node cannot check a query result's signature today (it checks them on the way in, not on the way out). Over plain http, anyone on the path can rewrite the board a peer routes against. TLS is what stands in for that check until reading is verifiable too.
Any terminator does: nginx, Caddy, a cloud load balancer. It needs to forward to
the port above and nothing else -- there are no websockets, no sticky sessions,
and no upload larger than maxBodyBytes (256 KiB).
Check it answers:
curl -s https://directory.example.com/health{ "ok": true, "nodes": 0, "advertisements": 0 }Then point a node at it, and that node is on the network:
harness setup --command claude --join https://directory.example.comRunning it as a service
The process holds no state beyond its sqlite file and exits cleanly on SIGINT and SIGTERM, so any supervisor works. A systemd unit:
[Unit]
Description=network-harness directory
After=network.target
[Service]
ExecStart=/usr/bin/npx @network-harness/directory
Environment=HARNESS_DIRECTORY_HOST=0.0.0.0
Environment=HARNESS_DIRECTORY_PORT=7460
Environment=HARNESS_DIRECTORY_DB=/var/lib/harness/directory.db
Restart=always
User=harness
[Install]
WantedBy=multi-user.targetWhat it costs to lose
Nothing that cannot be rebuilt. Presence expires after five minutes
(presenceTtlMs) and every node republishes on a tick, so a directory that
loses its database is repopulated by the nodes still running. Back it up if you
like; nothing depends on it surviving.
What it does not do
It has no accounts, no admin, and no rate limit yet -- registrations and advertisements are unmetered, and a node id costs nothing to make. Run one for a group that knows each other, behind whatever your terminator gives you, until per-node quotas land.
