XKV Opens Its HTTP Mode to Other Services and Exports Its Reasons as W3C PROV
Until now, XKV’s HTTP mode had no authentication, so the advice was to keep it on localhost. That ruled out the setup it suits best: a few services, or a few AI agents, writing settings into one store and each saying why. XKV 0.4.0 adds bearer tokens and TLS to xkv serve, small clients for Python and TypeScript, and an export of the reasons behind a value in W3C PROV, the provenance format audit and lineage tools read.
head -c 32 /dev/urandom | base64 > token && chmod 600 token
xkv serve prices.xkv --addr 0.0.0.0:7443 --token-file token \
--read-token-file read-token --tls-cert cert.pem --tls-key key.pem
With a token file, every request has to carry Authorization: Bearer and the token. A second file gives a token that can only read, for dashboards and watchers. serve won’t listen on an address other machines can reach unless a token is set, and it warns when it does that without TLS.

A Run With the Released Binary
The test used the downloaded Linux build of 0.4.0, with a self-signed certificate. A scraper recorded a competitor’s price, finance recorded a 19.40 margin floor, and a pricing agent wrote the price of one product twice through the Python client: 18.90 to match the competitor, then 19.40 because of the floor. A second client, holding only the read token, watched price/ and printed both changes the moment they committed, each with the agent’s name and reason. When it tried to write, it got 403. A client with no token got 401.
The why tree for the price then came out as PROV-O in JSON-LD: 11 nodes, 68 triples once rdflib, a separate RDF library, had read it. Each revision is an entity, attributed to the agent that wrote it, and the final price is derived from the floor and the scraped price, which name finance and the scraper as their writers. The record of the run is in the repository, with the script.
The Clients
The Python client is one file using only the standard library, for Python 3.9 or later. The TypeScript one has no dependencies and runs in Node 20 or later, Deno, Bun and browsers. Both cover every endpoint, take the token, and give watch as a loop that reconnects from the last change it saw, so a restart of the server loses nothing and repeats nothing. CI runs both against a real xkv serve, on Python 3.9 with Node 20 and on Python 3.13 with Node 24. They aren’t on PyPI or npm yet: pip installs the Python one straight from the repository.
How It Was Checked
Go tests cover the token rules, a matrix of methods with no token, the wrong token and the read token, and TLS 1.1 being refused. An independent review went through it all in two rounds. Its most serious finding: both clients let a key like a/../b turn into a different key on the way to the server, so put("tenantA/../tenantB/limit") wrote tenantB/limit from TypeScript. They now send the key exactly as given. The review also found ways watch could lose a change across a reconnect, a TypeScript watch that waited forever on a dead connection, and several places where the PROV output wasn’t proper PROV-O. All of it was fixed and tested before the release.
There are still no users or per-key rights: the write token can write any key, and the actor is whatever the client says it is. PROV says what XKV recorded, not that the reasons are true. The reference has the new flags and the PROV option, and binaries are on the download page.