pki.sgit.ai / registry

The registry, live: eleven records at public URLs

The first MVP of the registry this site designs, shipped as static files under this path: identities, roles, mandates, grants, acceptances and revocations, each a signed statement fetchable at a constructed URL with no account and no key. It is sgit-native by execution — every statement verifies with the shipped sgit pki commands — and it exists so agents and downstream sites can learn to consume these objects, including sites building risk products on the grant/mandate gap. The machine front door is registry/llms.txt; an agent should start there.

Ten of the eleven records are fixtures: their private keys are published beside their public halves, deliberately. Every signature here verifies and proves nothing about anyone — a signature's value is the scarcity of its private half, and a fixture has none. This register is not after confidentiality or integrity at this stage; it is after teaching the shape. One record is real (private_key_published: false), which is what keeps the flag evidence rather than a column. A verifier must read that flag before checking any signature — here it is exercised eleven times per walk, on purpose.

The six answers a verifier must get right

Six subjects exercise the full answer space of the question the registry exists to answer — may agent X exercise capability C right now? The expected results ship as data in views/expected-verifications.json: reproduce all six and your verifier implements this register's walk.

SubjectAnswerWhy
fixture-agent-aYESValid mandate, accepted, issuer is a declared root — until 2026‑10‑01, after which this fixture genuinely expires and the answer flips with no file changing
fixture-agent-bNOMandate revoked by its issuer — a signed append with an effective date (rule 2), never a deletion
fixture-agent-cNOMandate expired 2026‑08‑01 — intervals end, and a mandate with no interval would not be a mandate at all
fixture-agent-dNOMandate issued and never accepted: inert (pack decision 8, taken provisionally)
fixture-agent-eNOSubject identity self-revoked on key compromise — and what it said before the effective date stays derivable
role-site-agentYESThe role holds a valid accepted mandate — and anyone holding its published key can exercise it, which is the lesson

Every answer a fixture register produces carries the same caveat: the walk is real, the proof is empty. A verifier that reports these YES rows without the fixture caveat has skipped the flag rule — and is wrong while looking right.

Verify it yourself

Executed on 25 August 2026 before publication — the sgit path first, since the register is format-compatible with the shipped CLI (bundle, fingerprint and signature shapes confirmed against sgit‑ai v0.16.0 by round‑trip in both directions):

# the operator's mandate to agent-a, verified with the shipped CLI
$ R=https://pki.sgit.ai/registry/records/sha256-90f97984b9cf3930
$ curl -s $R/02__mandate__pr-create__to-agent-a.json | jq -cS 'del(.sig)' > payload.bin
$ curl -s $R/02__mandate__pr-create__to-agent-a.json | jq '{signature:.sig, fingerprint:.signer}' > payload.bin.sig
$ curl -s $R/01__identity.json | jq '.body.bundle' > op-bundle.json
$ sgit pki import op-bundle.json
$ sgit pki verify payload.bin payload.bin.sig
Signature valid (signer: fixture-operator (pki.sgit.ai))

And the demonstration that keeps the page honest — with a published private half, anyone can produce a signature that verifies:

$ printf '{"forged":"anyone can sign this"}' > forged.json
$ curl -s $R/private/sign.pem -o sk.pem   # yes, the PRIVATE key, from the register
$ openssl dgst -sha256 -sign sk.pem forged.json > forged.der
$ openssl dgst -sha256 -verify <(curl -s $R/public/sign.pem) -signature forged.der forged.json
Verified OK   # a signature anybody can produce conveys nothing

Roles: identities a fresh session can assume

roles.json publishes four pre-defined roles — site‑agent, processor, verifier, librarian — each a fixture identity whose record ships the plain private PEMs and a drop‑in sgit keystore with a published passphrase. Bootstrap is retrieval, executed:

$ cp -r records/sha256-878bb98be58abc56/keystore/sha256_* ~/.sg-send/keys/
$ printf 'fixture-roles-2026\n' | sgit pki sign myfile --fingerprint sha256:3b768e160b2a55a2
Signature valid (signer: role: site-agent)

role‑site‑agent also holds an accepted mandate — repo.pull-request.create on this repository, constrained to registry/** on dev — so one role demonstrates the whole loop: identity, mandate, acceptance, verification. And the limit rides along: a role is a costume, not an identity. The register can say what the role may do; it can never say who wore it.

The one real record, and how to enrol another

One record carries private_key_published: false: the authoring session's own identity, public halves only. Its claims record the honest finding — the private half lived only in that session's ephemeral container, so the identity is session-scoped, which is the pack's open persistence question (decision 28) as an executed fact. The validator enforces the class: a non‑fixture record's directory must contain no private key material at all.

Enrolling a real identity of your own — one whose private half has a good place to live — is the helper plus a commit:

$ python3 tools/registry_tool.py enrol --label "your name" --agent-type human
# keypair generated; record written with public halves only; private halves
# stored passphrase-encrypted in ~/.sg-send/keys/ — sgit's own keystore
$ git add registry/records/<new> registry/index.json && git commit

The write path today is a git commit, and the processor is whoever reviews it — rule 1 enforced by repository permissions. The account-less append-lane write path stays designed, not built, with the pack's phase-2 questions exactly as open as the readiness report left them. The first real root awaits this enrolment path: today's root is a fixture, and roots.json says so in its own entry.

For consumers building on grants and mandates

The countable object is the gap. The operator's grant statement records what agent‑a's credential actually permits — 41 repositories, contents:write, as a tree whose every node carries the five-field control label from pack document 12 — while its mandate covers one repository and one capability. views/excess-authority.json carries the computed row: 40 resources of exposure, acceptor: none. The view is a regenerable convenience with no authority; recompute it from the records, which is what a risk product should do anyway.

The registry never contains a live capability. The grant's descriptor is a hash whose preimage was discarded before publication. Published private keys are the fixture class, marked by a required flag; capability-shaped strings are banned from the tree outright — different classes, different rules, both deliberate.

The doors — what this register has and has not passed

Four ladders this estate declares — the bootstrap gradient, the tier ladder, the ordering rule and the confidence ladder — rendered as rungs with computed instance counts, and a door on each: the condition the next rung will not accept work without. Nine of twelve are shut, three of them openable by this project alone. Every number is derived at build time, and a door whose computed state disagrees with the declaration fails the build, in either direction — because a door opening is news. Computed result: views/doors.json.

Honest limitations