@agenticprimitives/registry-resolution
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
The composed typed-name resolver of spec 346: given a typed handle (rpedersen.me, [email protected],
[email protected], discovery.registry) and a caller posture, it returns the subject, its
derived type, the issuing context and the live relationship (for x@ctx names), the permitted deployment
bindings, the delegations it saw, and the registry/directory evidence — as six separate signals.
It never returns a trust score and never authorizes anything.
parseAgentName ─▶ checkTypedName (suffix ↔ on-chain atl:agentType ↔ root; fail closed)
│ x@ctx: issuance (posture-gated) ─▶ basis live? (membership · role gate · delegation) ─▶ ContextualAgentReferenceV1
▼
discovery policy (per-agent or the per-type default) ─▶ is THIS caller admitted? (one mechanism)
▼
publication via the caller's reference kind (ans-name | private-grant | direct-invitation) ─▶ bindings
▼
registry entries + directory evidence ─▶ TypedResolutionResultV1
Usage
import { resolveTypedName } from '@agenticprimitives/registry-resolution';
const out = await resolveTypedName('[email protected]', { posture: 'grant', requester, grantId, presentation }, ports);
if (out.ok) {
out.result.subject; // { agentId, derivedType: 'person', root: 'person', name, legacy: false, typeConsistent: true }
out.result.context; // { agentId: richcanvas.org's SA, derivedType: 'org', name: 'richcanvas.org' }
out.result.relationship; // { membershipId, roleAssignmentId?, delegationHash, current: true, basis: 'membership' }
out.result.bindings; // { host, agentCardUrl, a2aEndpoint, surfaces, publication } — from the signed publication
out.result.authority; // { note: 'resolution-is-not-authority', delegationsSeen: [...] }
out.result.evidence; // { registryEntries, assurance, directory }
} else {
out.reason; // 'unregistered' | 'type_mismatch' | 'issuance_not_found' | 'basis_not_current' | 'not_permitted' | …
}
ports (TypedResolverPorts) are all injected: the typed-naming read (AgentNamingClient.checkTypedName),
the context's issuance surface, delegation liveness, membership/role reads, the agent-resolution composed
resolver, registry evidence, and optionally directory evidence, workspace reads and per-agent policies.
Flows (spec 346 §9)
| Function | What it plans |
|---|---|
acceptConnectInvitation(invitation, acceptor, now) | shape + expiry + recipient checks; returns the grant + initial publication the invitee stores. The registry records nothing. |
planContextualNameIssuance(input, registryId) | after a join is accepted: the unsigned ContextualNameIssuanceV1 body (kind: 'reference', membership + delegation basis) + the CONTEXTUAL_NAME_ISSUED log event. |
planScopedNameIssuance(input, registryId) | a context issuing vault.svc@… / architecture.team@… in its own namespace (operated-by / chartered basis). |
revokeContextualName(issuance, registryId, now) | deactivates the contextual name; the canonical handle is untouched. |
Referral admission (§9.3) lives in registry-kit (admitRegistryEntry with a sponsor).
Posture defaults (spec 346 §8.1)
defaultDiscoveryPolicyForType(t) — person: public name, unlisted, grant-resolved; org / service / registry:
public; team / workspace: consented listing, authenticated resolution; treasury: unlisted,
grant-resolved. callerAdmittedBy(policy, posture) is the single admission rule.
What this package refuses to do
Hold state, open a transport, decide authorization, rank, or fall back. See CLAUDE.md.