Access
Access is inseam’s first-class permission layer over Source data. Envelopes resolve into durable Principals; declarative rules grant or deny per (Principal, Source); a live checkAccess recheck runs on every fetch. Access is the scope leg of the Connection / Source / Access split: Connection holds reach, Source holds addresses, Access holds scope.
How it fits
Section titled “How it fits”Two surfaces, split by package:
@inseam/access-contract—Principal,Identifier,Network,Host,Envelope,EnvelopeParty,SourceParticipant,AccessGrant, the rule AST (AccessConfig,Rule,Predicate,TargetSelector), theIdentifierKindDefinitionandCeremonyAdapterinterfaces, event payload shapes, and theAccessErrorhierarchy. Zero runtime deps.@inseam/core(Access contribution) —openAccessRegistry,AccessRegistry, thedefineAccessbuilder and predicate factories, the principal-resolver and access-projection materializers, and the egress filter.
The data model rides Store tables; the read and write paths ride the Events outbox. Two core-owned materializers register against the supplied EventsRegistry:
access.principal-resolverconsumescore.envelope_indexed, canonicalizes each party’s identifier, find-or-creates thePrincipal, and writessource_participantrows witheffectiveTrust = min(identifier.trust, party.trust).access.access-projectionconsumes envelope, rule-change, identifier-trust, and merge events; JOINs participants × rules × host owners; writesaccess_grantrows. Deny-wins. Rule changes write into a shadow projection and atomically swap.
Key pieces
Section titled “Key pieces”openAccessRegistry({ store, events })— host entry point. Boots the registry, registers the two core materializers, sets up the egress filter.defineAccess({ rules: [...] })— rule-set builder. Validated onsetRulesagainst the trust ladder and registered identifier kinds.- Predicate factories —
grant,deny,identifierEquals,identifierMatches,principalHasRole,sourceKindIn,roleIn,all,any,not, … checkAccess({ principalId, sourceId })— authoritative read path. Re-evaluates the current rule set against current trust state. Cheap, indexed; used on every fetch.listAccessibleSources(...)— projection-backed listing. Stale on a race with a rule change; callers needing authoritative state recheck per row.- Trust ladder — closed:
claimed<provider-asserted<verified. Plugins assert at mostprovider-assertedfrom envelope data;verifiedrows exist only viaprincipal.identifier_verified, which only registered ceremony adapters may emit.
Exact signatures and rule grammar: @inseam/access-contract API · arch/access/spec.md.
When to use this vs alternatives
Section titled “When to use this vs alternatives”Plugins contribute Access vocabulary, never rules. Two extension points:
- Identifier kinds — implement
IdentifierKindDefinition(akindname, ascopeDisciplinedescription, a deterministiccanonicalize). Register viaaccess.registerIdentifierKind. - Ceremony adapters — implement
CeremonyAdapter(aname,supportedKinds, an asyncrunreturning a signedCeremonyAttestation). Register viaaccess.registerCeremonyAdapter. Only registered adapters may produceprincipal.identifier_verified.
Rules themselves are host-owned. Plugin-defined roles MUST be plugin.scope-prefixed (e.g. "gmail.thread-owner"); the framework’s reserved role values are sender, recipient, cc, bcc, mentioned, owner.
If you find yourself wanting to gate data behind a check that isn’t expressible as (Principal, Source) → grant|deny, the right move is usually to add a new identifier kind or role, not to bypass Access.
See also
Section titled “See also”- LLM summary — dense reference for agents.
- Connection — Connection-owned setup is the entry point for owner / device Principals.
- Source — what grants attach to.
- Events — the outbox the materializers ride.
arch/access/design.md— why Access is a first-class layer and the trust ladder rationale.arch/access/spec.md— data model, rule AST, predicate vocabulary, projection + recheck read path, egress filter, errors, acceptance criteria.