Skip to content

CellarDoorExits/entry-door

cellar-door-entry

npm version tests license NIST

𓉸 Passage Protocol · exit-door · entry-door · mcp · langchain · vercel · eliza · eas · erc-8004 · sign · python

⚠️ Pre-release software — no formal security audit has been conducted. This project is published for transparency, review, and community feedback. It should not be used in production systems where security guarantees are required. If you find a vulnerability, please report it to hawthornhollows@gmail.com.

The arrival side. Verify where an agent came from and decide whether to let it in.

📌 v1.2 Stable Snapshot — Tagged reference point before v2 policy engine changes.

Ecosystem

Package Language Description
cellar-door-exit TypeScript Core protocol (reference impl)
cellar-door-exit Python Core protocol
cellar-door-entry TypeScript Arrival/entry markers ← you are here
@cellar-door/langchain TypeScript LangChain integration
cellar-door-langchain Python LangChain integration
@cellar-door/vercel-ai-sdk TypeScript Vercel AI SDK
@cellar-door/mcp-server TypeScript MCP server
@cellar-door/eliza TypeScript ElizaOS plugin
@cellar-door/eas TypeScript EAS attestation anchoring
@cellar-door/erc-8004 TypeScript ERC-8004 identity/reputation
@cellar-door/sign-protocol TypeScript Sign Protocol attestation

Paper · Website

Quick Start

npm install cellar-door-entry cellar-door-exit
import { quickExit, toJSON } from "cellar-door-exit";
import { quickEntry } from "cellar-door-entry";

// Agent exits Platform A
const { marker: exitMarker } = await quickExit("https://platform-a.example.com");
const exitJson = toJSON(exitMarker);

// Agent arrives at Platform B
const { arrivalMarker, continuity } = quickEntry(exitJson, "https://platform-b.example.com");

console.log(continuity.valid);           // true
console.log(arrivalMarker.departureRef); // urn:exit:...
console.log(arrivalMarker.subject);      // did:key:z6Mk...

The Passage Flow

The complete pipeline for agent passage between platforms:

EXIT → verify departure → evaluate admission → create arrival → sign → verify continuity → claim
import { quickExit, toJSON, generateIdentity } from "cellar-door-exit";
import {
  createArrivalMarker,
  signArrivalMarker,
  evaluateAdmission,
  OPEN_DOOR,
  scopeFromExitMarker,
  InMemoryClaimStore,
  verifyTransfer,
  validateArrivalMarker,
} from "cellar-door-entry";

// 1. Agent exits Platform A
const { marker: exitMarker } = await quickExit("https://platform-a.example.com");

// 2. Evaluate admission policy
const admission = evaluateAdmission(exitMarker, OPEN_DOOR);
if (!admission.admitted) throw new Error(`Denied: ${admission.reasons.join(", ")}`);

// 3. Derive capability scope from exit modules
const scope = scopeFromExitMarker(exitMarker);

// 4. Create and sign arrival marker
const arrival = createArrivalMarker(exitMarker, "https://platform-b.example.com", {
  capabilityScope: scope,
});
const dest = generateIdentity();
const signed = signArrivalMarker(arrival, dest.privateKey, dest.publicKey);

// 5. Claim the departure (prevent replay)
const store = new InMemoryClaimStore();
store.claim(exitMarker.id, signed.id);

// 6. Verify the full passage
const passage = verifyTransfer(exitMarker, signed);
console.log(passage.verified); // true

// 7. Validate marker structure
const valid = validateArrivalMarker(signed);
console.log(valid.valid); // true

Policy Engine (v2)

Composable, fail-closed policy engine for admission decisions. Cryptographic signature verification is built into the ceremony.

import { createPolicy, admit, CAUTIOUS, REQUIRE_MUTUAL } from "cellar-door-entry";
import { quickExit, generateKeyPair } from "cellar-door-exit";

// Build a policy with the fluent API
const policy = createPolicy("my-platform")
  .requireVerifiedDeparture()      // cryptographic proof required
  .onSelfOnly("probation")         // self-attestation gets probation
  .maxAge("24h")                   // reject stale markers
  .allowMinting({ requireJustification: true })  // fresh agents OK
  .build();

// Admit an arriving agent
const { marker } = await quickExit("https://origin.example.com");
const platformKeys = generateKeyPair();
const result = await admit(marker, {
  policy,
  platformIdentity: platformKeys,   // enables counter-signing
  destination: "https://my-platform.example.com",
});

if (result.admission.admitted) {
  console.log(result.arrivalMarker.id);              // urn:entry:...
  console.log(result.admission.counterSigned);        // true
  console.log(result.admission.policyApplied);        // "my-platform"
  console.log(result.counterSignedExitMarker);        // exit marker with platform's counter-signature
}

Preset Policies

Preset Description
CAUTIOUS Require verified departure, probation for self-only
REQUIRE_MUTUAL Require counter-signed (mutual) markers
REQUIRE_MUTUAL_WITH_ONRAMP Mutual required OR minting allowed (antitrust-safe)
PERMISSIVE Accept most markers, probation for unverified
LOCKDOWN Reject everything

Minting

Create arrival records for agents with no departure history:

import { mintAgent, bulkMint, createPolicy } from "cellar-door-entry";

const policy = createPolicy("onboarding")
  .allowMinting({ requireJustification: true })
  .build();

// Single mint
const result = await mintAgent({
  subjectDid: "did:key:z6MkNewAgent",
  justification: "Platform bootstrap",
  policy,
});

// Bulk migration
const bulk = await bulkMint(
  [{ subjectDid: "did:key:z6Mk1", justification: "Migration" }],
  { policy }
);

Events

import { AdmissionEventEmitter } from "cellar-door-entry";

const emitter = new AdmissionEventEmitter({
  onError: (err, event) => auditLog.error(event.type, err),
});

emitter.on("agent:admitted", ({ record }) => { /* audit */ });
emitter.on("agent:rejected", ({ record }) => { /* alert */ });
emitter.on("agent:quarantined", ({ record }) => { /* review queue */ });
emitter.on("agent:minted", ({ record }) => { /* onboarding */ });

await admit(marker, { policy, emitter });

SQLite Claim Store

Production-ready claim tracking with WAL mode and GDPR erasure:

import { SqliteClaimStore } from "cellar-door-entry";

const store = new SqliteClaimStore("./claims.db");
await admit(marker, { policy, store });

// GDPR: erase all records for a subject
await store.eraseSubject("did:key:z6MkAgent");

// Stats
const stats = await store.stats();

Modules (v1)

Simple Admission Policy

Declarative rules for basic admission decisions.

import { evaluateAdmission, OPEN_DOOR, STRICT, EMERGENCY_ONLY } from "cellar-door-entry";
import type { AdmissionPolicy } from "cellar-door-entry";

// Preset policies
evaluateAdmission(exitMarker, OPEN_DOOR);       // Accept if signed
evaluateAdmission(exitMarker, STRICT);           // Voluntary, <24h, modules required
evaluateAdmission(exitMarker, EMERGENCY_ONLY);   // Only emergency exits

// Custom policy
const policy: AdmissionPolicy = {
  requireVerifiedDeparture: true,
  maxDepartureAge: 3_600_000,          // 1 hour
  allowedExitTypes: ["voluntary"],
  requiredModules: ["lineage"],
};
const result = evaluateAdmission(exitMarker, policy);
// → { admitted: boolean, conditions: string[], reasons: string[] }

Probation

Track probationary status on arrival markers.

import { createProbationaryArrival, isProbationComplete } from "cellar-door-entry";

const arrival = createProbationaryArrival(exitMarker, "https://platform-b.example.com", {
  duration: 30 * 86_400_000,  // 30 days
  restrictions: ["no-api-write", "limited-storage"],
  reviewRequired: true,
});

// Check later
isProbationComplete(arrival);                          // false (too early)
isProbationComplete(arrival, new Date("2026-04-01"));  // true (30+ days later)

Capability Scope

Determine what the arriving agent can do.

import { scopeFromExitMarker, createRestrictedScope, mergeScopes } from "cellar-door-entry";

// Derive from EXIT marker modules
const scope = scopeFromExitMarker(exitMarker);
// → { allowed: ["basic-interaction", "identity-continuity", ...], denied: [] }

// Manual restriction
const restricted = createRestrictedScope(["read"], ["write"], "2026-12-31T00:00:00Z");

// Merge (denied wins)
const merged = mergeScopes(scope, restricted);

Claim Tracking

Prevent replay attacks; each EXIT marker can only be claimed once.

import { InMemoryClaimStore } from "cellar-door-entry";

const store = new InMemoryClaimStore();
store.claim("urn:exit:abc", "urn:entry:xyz");  // true (claimed)
store.claim("urn:exit:abc", "urn:entry:new");  // false (already claimed)
store.isClaimed("urn:exit:abc");               // true
store.revoke("urn:entry:xyz");                 // unclaims the exit

Implement the ClaimStore interface for production backends (Redis, DB, ledger).

Revocation

Revoke arrivals after the fact.

import { createRevocationMarker, verifyRevocationMarker, isRevoked } from "cellar-door-entry";

const revocation = createRevocationMarker(signedArrival, "fraud detected", privateKey, publicKey);
verifyRevocationMarker(revocation);           // { valid: true, errors: [] }
isRevoked(signedArrival.id, [revocation]);    // true

Passage Verification

End-to-end verification of the EXIT → ENTRY chain.

Note: The API currently exports verifyTransfer(). This will be renamed to verifyPassage() in v0.2.0.

import { verifyTransfer } from "cellar-door-entry";

const record = verifyTransfer(exitMarker, signedArrival);
// → { verified: boolean, errors: [], passageTime: 1234, continuity: {...} }

Input Validation

Validate arrival marker structure and fields.

import { validateArrivalMarker } from "cellar-door-entry";

const result = validateArrivalMarker(marker);
// Checks: context, id format, DID format, timestamp, size limits, etc.

API Reference

Function Description
verifyDeparture(exitMarker) Verify an EXIT marker, return structured result
verifyDepartureJSON(json) Parse and verify an EXIT marker from JSON
createArrivalMarker(exit, destination, opts?) Create a linked arrival marker
signArrivalMarker(marker, privateKey, publicKey) Sign an arrival marker with Ed25519
verifyArrivalMarker(marker) Verify an arrival marker's signature
verifyContinuity(exit, arrival) Verify the link between departure and arrival
quickEntry(exitJson, destination, opts?) One-shot: parse, verify, create, sign, check continuity
evaluateAdmission(exitMarker, policy, now?) Evaluate admission against a policy
createProbationaryArrival(exit, dest, config, opts?) Create arrival with probation
isProbationComplete(arrival, now?) Check if probation has elapsed
scopeFromExitMarker(marker) Extract capabilities from EXIT modules
createRestrictedScope(allowed, denied, expires?) Create a capability scope
mergeScopes(a, b) Merge two scopes (denied wins)
InMemoryClaimStore In-memory claim tracking
createRevocationMarker(arrival, reason, privKey, pubKey) Create a signed revocation
verifyRevocationMarker(marker) Verify revocation signature
isRevoked(arrivalId, revocations) Check if an arrival is revoked
verifyTransfer(exit, arrival) Full end-to-end passage verification
validateArrivalMarker(marker) Validate marker structure and fields

Continuity Checks

verifyContinuity validates:

  • Reference: Arrival's departureRef matches the EXIT marker's id
  • Subject: Same DID on both markers
  • Origin: Arrival's departureOrigin matches EXIT's origin
  • Temporal: Arrival timestamp is after departure timestamp
  • Cryptographic: EXIT marker signature is valid

License

Apache-2.0

About

ENTRY Protocol: policy-based admission, verification, and arrival records for AI agents

Topics

Resources

License

Code of conduct

Contributing

Security policy

Stars

Watchers

Forks

Packages

 
 
 

Contributors