How issuance works
The page builds a manifest from your inputs. The two behavioral attestations start false, because they are claims about how the agent behaves that no API can confirm; you set them yourself. The browser then signs a ManifestProof, which binds the manifest by SHA-256 digest, with Ed25519 over RFC 8785 canonical JSON.
The registration route validates the manifest against the strict schema, checks the digest binding, the key role and controller, and the signature, and stores the record. After issuance the page offers the card link, the JSON envelope, an HTML embed, README markdown and a curl one-liner.
Client-side key custody
Browser signing uses @noble/curves with its own JCS implementation in packages/web/lib/client-crypto.ts. Cross-implementation tests prove that @agenid/core accepts a browser-produced proof. Two independent canonicalizers must agree byte for byte, or the protocol quietly forks.
Server-side operator key generation was deleted outright rather than hardened. Its encryption helper silently wrote the key as plain hex whenever its secret was unset. The registry now never holds an operator private key, by construction.
The clock truncation bug
Both the write and read paths stripped fractional seconds from timestamps. Truncation only ever moves an instant backward, so a browser that signed and posted within the same second produced a created_at later than the registry's truncated now, and the registry rejected its own fresh proof as not_yet_valid. The same truncation on the read path would have rendered a brand-new agent's badge as PROOF INVALID.
Truncation is gone. A bounded skew policy was added alongside: a proof created up to 120 seconds ahead of the registry is evaluated at its own created_at, and beyond that the request fails with clock_skew_too_large. registered_at is always the registry's clock, and proof verification itself remains strict.
What L1 means, and what it does not
L1_REGISTERED means the registry validated the schema, the digest binding and the operator's signature. It is a self-declaration and renders amber, never emerald. The reference deployment at agenid.com issues nothing above L1_REGISTERED today: L2 and higher require a VerificationAssertion signed by a root authority key, and that key has not been created yet. L5 is reserved and is not issuable at all.
Which agent is acting is not the same question as what it is allowed to do. AgenID answers the first. Protocol v1.1.1 defines no signed authorization object, so permission stays with the operator and with the party on the other side.
How to try it
Open /issue, register a test agent and save the key file when offered. Then resolve the identifier at /verify and re-check the envelope yourself. The operator onboarding guide covers the command-line path, which signs locally in the same way.