Entity Card

The typed, DID-anchored identity card that KYA-OS entities publish for discovery, with per-request proof riding on top.

What an Entity Card is

The Identity Layer gives every participant a DID and key material. The Entity Card is the object built on top of that DID: a typed description of the entity that can be published wherever peers look for it. The card profile is specified in SPEC-ENTITY-CARD.md (v1.1), and the published JSON Schema (schema.kya-os.org/v1/protocol/identity/card/v1.1.0) declares additionalProperties: false — a conformant card carries no unknown top-level properties.

Every card declares exactly one entityType from a closed set, so a verifier knows what kind of participant it is dealing with before any request is made:

entityTypeThe participant
mcpAn MCP server exposing tools and resources
agentAn autonomous agent acting for a principal
clientAn OAuth/MCP client; the natural product of the CIMD on-ramp
verifierA component that checks cards, proofs, and delegations
humanA person acting as a delegating principal (typically did:key)

tool and skill are not entity types — they are sub-resources declared inside a card's capabilities.

Claim-minimalism: assert locators, prove everything else

A card asserts only identity, type, declared capabilities, and accountability locators. Everything trust-bearing is proven by referenced, signed credentials that a verifier resolves and checks:

  • responsibleParty — the entity ultimately accountable: verified as the root issuer of the entity's delegation chain (via delegationRef), never taken on assertion
  • principal — the immediate human delegator, when distinct from the Responsible Party
  • attestations — resolvable signed credentials (capability attestations, KYC/KYB identity verification) about the entity or its Responsible Party
  • conformanceLevel — a derived summary (L1/L2/L3). A verifier ignores it on input and recomputes it: L1 is key possession, L2 adds credential-attested capabilities and accountability that verify offline, L3 adds a live per-request proof-of-possession with revocation freshness

Anchoring

The card's canonical home is a KyaOsEntityCard service entry on the entity's did:web DID document:

{ "id": "#kya-os-card", "type": "KyaOsEntityCard",
  "serviceEndpoint": "https://host/{path}/card.json" }

A bare did:web:host org root has no path segment to derive card.json from, so it additionally publishes at the well-known path /.well-known/kya-os-card.json — origin-authenticated on the entity's own host, mirroring did:web's own /.well-known/did.json. The card binds the key that will sign per-request proofs (via the cnf.jkt thumbprint), so discovery and runtime verification refer to the same key. did:key entities have no web home: their cards are supplied directly, never resolved by discovery.

Four discovery projections

One canonical card is projected onto the four rails peers already index. Each projection is a pure function of the card and points back at the same canonical card.json, so a verifier always lands on one source of truth. Discovery is not the security boundary — it only tells a peer where to look and what to expect. The proof does the verifying.

#RailProjection
1MCP server.json / catalog.json _metaThe reverse-DNS key org.kya-os/card: either an inline claim-minimal summary or a lazy-fetch org.kya-os/cardRef
2A2A AgentExtensionAn entry in AgentCard.capabilities.extensions[] with URI https://kya-os.org/a2a/ext/entity-card/v1, required: false — projected only for entityType: "agent"
3NANDA AgentFactsKYA-OS populates NANDA's owner slot from responsibleParty; the uniquely-KYA-OS fields (kya:entityType, kya:proofProfile, …) ride a kya: JSON-LD context
4MCP catalog.json index entryAlways by-ref (org.kya-os/cardRef), keeping the index cheap
Loading diagram...

Every projection obeys one graceful-degradation contract: an unaware peer ignores the KYA-OS layer without rejecting the underlying rail's document, and a stripped projection degrades to a fetch of the canonical card.json — never to a hard failure. Resolution follows attacker-influenced URLs, so every outbound fetch (card, DID document, JWKS, status list) goes through a mandatory SSRF-hardened SafeFetch: https-only, public-unicast only, resolve-once-and-pin, same-origin redirects, size and time caps.

Per-request proof rides on top

Discovery ends where verification begins. Once a peer has the card, every request carries a self-contained proof under _meta["org.kya-os/request-proof"] and every response carries _meta["org.kya-os/response-proof"]. The proof object names its profile in its prf field — org.kya-os/proof.v1 — and is signed by the key the card pinned with cnf.jkt; when the authorization server also sender-constrains its token, token.cnf.jkt === proof.cnf.jkt === thumbprint(resolve(kid)) threads token possession to per-request possession through one DID key. There is no separate handshake: the card is the standing identity, and the proof re-establishes control on every call. (For one major version, verifiers also read the earlier draft's org.kya-os/proof@1 carrier key and profile id.)

Delegation follows the same key discipline: the recommended delegate subject is a fresh, single-purpose did:key minted per delegation — the identifier is the key, so there is nothing to rotate, and the leaf delegate a verifier recomputes from the chain must equal the request-proof key. See the Verification Protocol for the request/response proof flow.

Next steps