@agenticprimitives/agent-profile
v1.0.0-alpha.26
Published
Agent identity SDK: AP-native Canonical Agent Profile (CanonicalAgentProfileV1) + signed profile bundle, CAIP-10 nativeId helpers, endpoint verification methods, and the A2A 1.0 Agent Card model (./a2a: JCS canonical bytes, ES256 JWS, EIP-712 Smart Agent
Maintainers
Readme
@agenticprimitives/agent-profile
Part of Agentic Primitives — the open-source trust substrate for agentic applications: identity that can sign, authority checked at act time, evidence the owner carries. Developer kit · All packages
A profile describes the identity; it never becomes the identity. Agent discovery is consolidating right now — on-chain registries, DNS/PKI agent naming, Hedera-style profiles, A2A cards, and MCP registries. Each standard wants to be the place an agent "lives." This package takes the other position: every agent already lives at one canonical ERC-4337 Smart Agent address, and a profile is an AP-native, typed, content-hashed manifest about that address (ADR-0010). Registry entries in any standard are external projections/facets that back-link to the same anchor — so one identity serves all of them, and no registry can quietly fork who the agent is.
Part of agenticprimitives — the trust substrate for the agent economy: one canonical Smart Agent identity with custody, delegation, naming, credentials, and audit evidence designed as one system.
Where agent-naming maps names → addresses, this package maps addresses → typed profiles and optional endpoint-control proofs: the CanonicalAgentProfileV1 schema, deterministic content hashing for on-chain anchoring, and CAIP-10 nativeId helpers for cross-registry back-links. Since spec 347 it also owns the A2A 1.0 Agent Card model (./a2a) — a different object, see below.
Layer: Discover — a profile facet (not login — that is
connect-auth; not canonical identity — that isagent-account). Canonical key: the Smart Agent address the profile describes.
Profile ≠ A2A card
| | CanonicalAgentProfileV1 (root) | A2AAgentCardV1 (./a2a) |
| --- | --- | --- |
| Answers | what is this agent, who operates it, what does it claim | what does THIS A2A server do and how do I talk to it |
| Shape | AP-native, discriminated on type | A2A 1.0 Agent Card (supportedInterfaces, capabilities, skills, securitySchemes, signatures) |
| Canonical bytes | sorted-key canonical JSON → keccak (profileContentHash, on-chain metadata-hash) | RFC 8785 JCS minus signatures → sha256 (cardContentDigest) |
| Proof | SignedCanonicalProfileBundleV1 (ERC-1271 by the SA) | ES256 JWS (any A2A client verifies) plus SmartAgentCardBindingV1 (EIP-712, ERC-1271 — AP verifiers) |
AgentCard, SignedAgentCardBundleV1, hashAgentCard, buildSignedAgentCardBundle, verifySignedAgentCardBundle still compile as deprecated aliases for one release (spec 347 §0.3, ADR-0062).
Use this when
- You author or validate a
CanonicalAgentProfileV1(person, org, service, treasury, MCP server, multisig). - You inherit, curate, validate, sign, release or import an A2A Agent Card (
./a2a) with field-level provenance and a Smart Agent binding. - You need a deterministic
profileContentHashfor the on-chainmetadata-hashanchor — so a tampered profile is detectable by anyone holding the hash. - You need CAIP-10
nativeIdencode/decode (strict encode, permissive decode) as a portable back-link to the canonical SA (ADR-0008). - You need endpoint-verification methods (DNS TXT, signed URL, HTTP challenge, verifiable presentation) — Phase 2+.
- You build encoded calls to register or update on-chain profile anchors.
Do not use this for
.agentnames or namehash —agent-naming.- Smart Agent deploy / UserOps —
agent-account. - Passkey / SIWE / JWT —
connect-auth. - Trust-fabric edges —
agent-relationships. - UAID string generation — refused by design (ADR-0008); we expose
nativeIdand consumers derive UAIDs locally.
Install
Workspace-internal; not yet published.
pnpm add @agenticprimitives/agent-profile60-second quickstart
import {
canonicalProfileJson,
profileContentHash,
buildCaip10Address,
type CanonicalAgentProfileV1,
} from '@agenticprimitives/agent-profile';
const canonicalAddr = '0x0000000000000000000000000000000000000003' as const;
const profile: CanonicalAgentProfileV1 = {
type: 'person',
displayName: 'Alice',
};
const hash = profileContentHash(profile);
const nativeId = buildCaip10Address({
namespace: 'eip155',
reference: '84532',
address: canonicalAddr,
});
// Anchor hash + nativeId on chain via agent-naming records or profile resolver.A2A card in 60 seconds
import {
inheritCardBase, draftFromBase, applyOverride, createRelease, transition, attachSignature,
generateA2ACardSigningKey, signA2ACard, verifyA2ACardSignatures, importA2ACard,
} from '@agenticprimitives/agent-profile/a2a';
const now = new Date().toISOString();
const base = inheritCardBase({
profile, names: { primary: 'alice.svc.agent' },
surfaceCards: toCardProjectionSet(catalog), // surface-catalog — the only source of inherited skills
runtimeCapabilities: { streaming: false, pushNotifications: false },
deployment: { host: 'https://alice.agent.example', a2aUrl: 'https://alice.agent.example/api/a2a' },
agentVersion: '2.0.0', now,
});
let draft = draftFromBase(base, { cardResourceId: 'card_01', now });
draft = applyOverride(draft, '/description', 'Curated copy.', { now }); // recorded, reviewable
let release = createRelease(draft, { releaseNumber: 1, agentVersion: '2.0.0', now,
validation: { environment: 'production', catalogSkills: base.card.skills, runtimeCapabilities: {} } });
release = transition(release, 'approvalPending', { now });
release = transition(release, 'approved', { now, approval }); // ApprovalRefV1 names the exact digest
const key = await generateA2ACardSigningKey(); // ES256, kid = RFC 7638 thumbprint
const signed = await signA2ACard(release.unsignedCard, { privateKey: key.privateKey, kid: key.kid });
release = attachSignature(release, { signedCard: signed.card, signature: signed.signature });
// A non-AP client:
await verifyA2ACardSignatures(signed.card, { keys: (kid) => (kid === key.kid ? key.publicJwk : undefined) });
// Importing someone else's card: bytes kept, signatures verified BEFORE normalizing, unknown fields flagged.
const { imported, diagnostics } = await importA2ACard(bytes, { verifyKeys });How it's different
The reference points are registry and agent-card ecosystems, but this package defines the AP-native primitive:
- Anchor, not authority. In registry-first designs, the registry entry is the agent, and each registry mints its own notion of identity. Here the
AgentCardis AP-native typed JSON discriminated ontype, and every external registry facet must back-link to the canonical Smart Agent via CAIP-10nativeId(spec 220 §4). One agent, many registries, zero identity forks. - Tamper evidence built in.
profileContentHashis deterministic canonical JSON — sorted keys, fixed numeric format — matching the on-chainmetadata-hashpredicate. Two semantically equal profiles hash identically; a mutated profile cannot pass against its anchor. - Endpoint claims are not endpoint proof. A profile may claim an MCP or A2A URL;
VerificationMethodis the explicit, caller-selected proof that the Smart Agent controls it. We never silently pick a verification method — you always know what "verified" meant. - CAIP-10 done strictly. Encoders reject unknown namespaces (Phase 1: eip155, hedera, solana); decoders accept any grammar-valid CAIP-10 string for forward compatibility.
Main concepts
- CanonicalAgentProfileV1: AP-native typed JSON discriminated by
type, with type-specific sub-objects (AiAgentProfile,McpServerProfile,MultisigProfile,ServiceProfile). - A2A Agent Card (
./a2a):A2AAgentCardV1+ draft / release /FieldBindingV1provenance (inherit | override | computed | manual), purevalidateA2ACard(stableDIAGNOSTIC_CODES, incl.CATALOG_DIVERGENCEandCAPABILITY_UNVERIFIED), lifecycledraft → validated → approvalPending → approved → signed → published → superseded | deprecated | revoked. - Distribution (
AgentDistributionV1, spec 347 §8.5): how to OBTAIN AND RUN the agent's software —acp?(ACP conformance, the eligibility flag for a hosted ACPregistry.json),version?(implementation semver),npx/uvx{ package, args?, env? },binary[<ACP_PLATFORMS>] { archive (https, no .dmg/.pkg/.deb/.rpm), cmd, sha256?, args?, env? }— field names verbatim from the ACP registryagent.schema.json. Stored as the SA-keyedDISTRIBUTION(atl:distribution) string property in JCS form:validateDistribution(pure,string[]issues) ·encodeDistribution(throws on invalid) ·decodeDistribution(fail-closed →null) ·buildSetDistributionCall. Public on-chain data by construction — never put a secret inenv. - Profile facet:
metadata-uri+metadata-hashpointing at the canonical SA. - CAIP-10
nativeId: the cross-registry back-link; must match the SA on EVM chains. - Verification: proves an MCP/A2A URL is controlled by the SA (distinct from naming).
See docs/concepts.md.
Subpath exports
@agenticprimitives/agent-profile/caip10— CAIP-10 helpers only (no client baggage).@agenticprimitives/agent-profile/profile— canonical JSON + content hash.@agenticprimitives/agent-profile/card— signed canonical-profile bundle.@agenticprimitives/agent-profile/a2a— A2A 1.0 Agent Card model: JCS canonical bytes, ES256 JWS, EIP-712 Smart Agent binding, field provenance, validation, import, release lifecycle.
Security invariants
- Profile content-hash is deterministic (canonical JSON).
- Card canonical bytes are RFC 8785 JCS (never the sorted-key
canonicalizeJson); signature and binding verification are fail-closed; import verifies before it normalizes; validation refuses secret material, private URLs and vault references in a card. - No raw passkey material in profiles — only
credentialIdDigest. - Verification methods are explicit, not auto-selected.
- No UAID generation (ADR-0008).
See docs/security.md and AUDIT.md.
Documentation map
docs/concepts.md— profile facet vs canonical SA.docs/api.md— public API guide.docs/security.md— invariants.docs/troubleshooting.md— common errors.docs/migration.md— migration notes.CLAUDE.md— agent routing.spec.md— spec pointer.
Validation
pnpm check:agent-profile
pnpm check:forbidden-termsStatus
Phase 1 — pure helpers + client skeleton. The schema, CAIP-10 helpers, and content hashing are real and tested; AgentIdentityClient reads throw I Phase 2 and writes throw I Phase 4 — they are stubs by design, and the shape is locked for authoring today. Beyond that: testnet/pilot-ready; production launch is gated on the public checklist in the root README.md, including third-party contract audit and governance key rotation. Track every security finding live in docs/audits/findings.yaml.
License
UNLICENSED.
