Registry quickstart
Outcome. Your own listing Registry: a discovery index with your chosen read/write access policy and filter vocabulary, wired to sellers and buyers.
Public terminology on this site is Registry. The synchronized source
file is docs/indexer-quickstart.md — "indexer" survives at the pinned
revision only in that filename and in internal identifiers; the document
itself, reproduced below, says "listing registry" throughout.
Before you begin
- Work from a clean SCM checkout at the revision shown below.
- Install Docker Engine and Docker Compose v2 on the Registry host.
- Decide whether reads and writes are public or bearer-token gated before distributing participant configuration.
- Generate new operator secrets; never reuse the placeholders in the guide.
Clone SCM and select the documentation pin before running the first build command:
git clone https://github.com/arkhai-io/simple-compute-market.git
cd simple-compute-market
git checkout --detach 648682c67a26caf9283492e999923ab6ca1206ee
Environment. Every command below runs on the host where you operate the Registry (Docker + Compose v2). A Registry is a discovery role only: it never negotiates, settles, or fulfills. Where the synchronized body says "vetted sellers," read that as sellers holding write authorization. An API key does not establish real-world identity, capacity, availability, or performance.
How to stand up your own listing registry. Reasons to run one:
- Curate which sellers can publish and which buyers can query (bearer-token auth, §6).
- No third-party rate limits.
- Custom
filter-spec.yaml— the vocabulary forgpu_model,region, etc. is per registry. - Solo testing — no fanout.
compose/seller.yml is registry-agnostic, so a listing registry can run on
the same host as a seller or anywhere else. Co-location is only deployment
convenience: the registry remains a discovery role, while the storefront
remains the seller's negotiation, settlement, and fulfillment role. See
roles.md for the role model.
1. Build the image
make build-registry
Produces arkhai:registry.
2. Configure
cp config.registry.env.example config.registry.env
$EDITOR config.registry.env
Fill in:
REGISTRY_ADMIN_API_KEY— operator-only secret used to mint/revoke per-user keys at/admin/api-keys. Generate withopenssl rand -hex 32.REGISTRY_BOOTSTRAP_API_KEY— the bearer token sellers and buyers will use until per-user keys are minted. Sameopenssl rand -hex 32pattern. This is the shared secret you give out.
The example file gates reads and writes independently and ships with
both on (REGISTRY_REQUIRE_READ_API_KEY=true,
REGISTRY_REQUIRE_WRITE_API_KEY=true) — a private listing registry where buyers
hold read keys and sellers hold write keys.
For a fully public listing registry (anyone can publish and query) set both to
false and drop the two key vars. For an open market — public
discovery, publishing limited to vetted sellers — set only
REGISTRY_REQUIRE_WRITE_API_KEY=true and hand write keys to sellers.
3. Bring it up
docker compose -f compose/registry.yml up -d
# or, sharing a docker network with a seller stack:
docker compose -f compose/seller.yml -f compose/registry.yml up -d
The compose file mounts a named volume at /app/data so the sqlite
state persists across restarts.
4. Wire sellers and buyers
In each storefront / buyer TOML:
[registry]
urls = ["http://<REGISTRY_HOST>:8080"]
When the listing registry and seller share a docker network, use the service
name: urls = ["http://registry:8080"].
5. Checks
curl -sf http://<REGISTRY_HOST>:8080/health
docker compose logs registry | grep -i "JIT.*Indexed agent"
curl -s http://<REGISTRY_HOST>:8080/filter-spec | jq
# Listings — note the full canonical agent ID, URL-encoded:
curl -s "http://<REGISTRY_HOST>:8080/agents/eip155%3A84532%3A0x8004A818BFB912233c491871b3d84c89A494BD9e%3A<N>/listings" \
| jq
Verify an attributed publisher's listings directly — omit the header only when reads are intentionally public:
curl -s "http://<REGISTRY_HOST>:8080/listings?publisher=<SIGNING_WALLET_ADDRESS>" \
-H "Authorization: Bearer <read_api_key>" | jq '.items'
6. Bearer-token auth
config.registry.env.example ships with both gates on. To disable auth
(fully public listing registry) set REGISTRY_REQUIRE_READ_API_KEY and
REGISTRY_REQUIRE_WRITE_API_KEY to false and drop the two key vars.
Flow:
- Admin mints/revokes per-user keys:
POST /admin/api-keyswithAuthorization: Bearer <REGISTRY_ADMIN_API_KEY>. The request body takesscope(readfor buyers,writefor sellers; defaults toread). A write key also satisfies read routes. - Sellers and buyers send
Authorization: Bearer <api_key>on every request, configured via each side's[registry.auth]block. Keys must match the URL in[registry] urlsexactly (scheme, host, port, no trailing slash).
In the seller / buyer TOML:
[registry.auth]
"http://<REGISTRY_HOST>:8080" = "<api_key>"
What success looks like
/health returns success, /filter-spec returns the vocabulary this Registry
accepts, the container retains its SQLite state across a restart, and an
authorized participant can read or publish according to the two gates you
configured. An empty listing response is valid; it is not a failed Registry.
If a check fails
- A
401from an intended public read means the read gate is still enabled. - A
401or403with a bearer token usually means the token scope is wrong or the participant's[registry.auth]key does not exactly match the configured URL. - A healthy process with no persisted rows usually means the expected named volume is not mounted.
Next steps
Continue to Registry authentication and topology to mint per-participant credentials and verify revocation.