@agenticprimitives/admission
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
Admission contracts for the Agentic Primitives Edge — the boundary between external agent intentions and internal agent capabilities.
Architect-of-record: spec 339 · ADR-0057
HTTPS is required.
mTLS is optional.
Application-level identity resolution and Admission are always required.
What it is
Four questions that must stay separate, in four shapes that cannot substitute for one another:
| Question | Shape |
|---|---|
| What did the transport prove? | OptionalTransportEvidence — never sufficient alone |
| What authenticated the caller? | OAuthEvidence / RequestProofEvidence |
| Who is the caller, canonically? | CanonicalActorContext — resolved, never claimed |
| What may they do? | AdmissionRequest → AdmissionDecision → AdmissionGrant |
Plus ExactMcpInvocationRequest for the private gateway, where a grant is re-checked against exact
arguments and live delegation.
Why the invariants are code
The architecture's claims are all "X is not Y" — a certificate is not an owner, a SPIFFE ID is not an agent, a grant is not a tool permission. Those survive review and then die in implementation, because the mistake never looks like one:
if (req.transport.mtls) { /* trusted peer */ } // a real handshake; a wrong conclusion
A type cannot catch that — mtls: true is a perfectly good boolean. So:
import { checkAdmissionInvariants } from '@agenticprimitives/admission';
const violations = checkAdmissionInvariants(request);
// mTLS-only, no token → OAUTH_TOKEN_REQUIRED
// "a TLS connection, mutual or not, authenticates no principal"
[] means the request is coherent enough to evaluate. It does not mean admit — relationship,
delegation, capability, entitlement and policy are all still ahead of it, and none of them live here.
Zero runtime dependencies
No viem, no provider SDK, no SPIFFE, no transport. Anything needing I/O is a port, not an import.
Enforced by pnpm check:optional-package-boundaries.
Install
pnpm add @agenticprimitives/admission
MIT.
Credential presentations and HTTP signatures
credentialPresentationEvaluator (CREDENTIAL_PRESENTATION_CONTRIBUTOR) admits a zero-knowledge credential
presentation as evidence at the door: the verdict names the issuer facet, the predicate digest, the nullifier grade and
the status sequence, and grants nothing. verifyHttpSignature (HTTP_SIGNATURE_CONTRIBUTOR, RFC 9421) records an HTTP
message signature as transport evidence — never authentication, never authority.
Reference
Agent ids are ERC-4337 accounts, not names. principalAgentId, actingAgentId and targetAgentId are CAIP-10 ids that
resolve to a 20-byte address (ADR-0010). Spec 339 as authored used urn:ap:agent:…; that is refused here, because a URN
is a name a namespace operator can reassign. runtimeId is exempt: a deployment is not an account. agentAddressOf
parses; it never resolves a name.
Not edge-runtime. edge-runtime asks the ingress question (route, headers, body size, abuse limit) and is
Cloudflare-shaped; its type is EdgeIngressRequest. This package asks the semantic one, and the canonical
AdmissionRequest lives here. One word for both is how a route check ends up standing in for an authority decision.
mTLS is optional, with three meanings kept apart. createTransportAssuranceEvaluator is the only place transport can
affect a decision: no certificate is normal (no rule means ALLOW); minimumAssurance denies below the bar
(MTLS_REQUIRED_FOR_PROFILE — requiring mTLS is policy, never transport deciding for itself); preferredAssurance with
constraintsBelowPreferred narrows instead. A certificate can only raise the bar; a test asserts it cannot turn another
evaluator's DENY into an ADMIT. Evidence comes from edge-cloudflare.transportEvidenceFromRequest; the level is measured
with observedTransportAssurance, never the self-reported label.
Layout. src/types.ts holds the contracts, each commented with the collapse its shape prevents. src/ports.ts holds the
injected interfaces and the only two extension points, both pointing inward. src/invariants.ts holds the
non-equivalences as code, because types cannot catch if (mtls) { trusted }.
Claims this package makes checkable. Transport evidence is never application authentication
(hasApplicationAuthentication). Assurance is what was validated, not what was claimed. A workload identifier is not an
agent; a binding must exist and be active. A grant is a door, not a key (checkInvocationAgainstGrant refuses an invocation
with no delegation). An empty capability ceiling admits nothing. An RFC 9421 HTTP signature is transport evidence only
(verifyHttpSignature → optionalTransportEvidence.httpSignature, spec 442 §6): the key is a resolver port, the invariant
set is identical with and without it, and tag: payment grants nothing.