# What Are Gatekeepers in Cloudflare OS? A Technical Guide to Capability-Based Adapters

> Discover Cloudflare OS Gatekeepers: capability-based adapters enabling AI gadgets to access external services. Learn about their three-layer architecture, permissions, and audit trails.

- Repository: [Cloudflare/cloudflare-os](https://github.com/cloudflare/cloudflare-os)
- Tags: deep-dive
- Published: 2026-09-04

---

**Gatekeepers in Cloudflare OS are capability-based adapters that expose external services to AI-driven gadgets through a three-layer architecture of Durable Objects, enforcing fine-grained permissions and audit trails via an ApprovalQueue.**

Cloudflare OS—internally codenamed the "Gadgets Workshop"—uses Gatekeepers to safely bridge AI agents with third-party APIs like Google Workspace, GitHub, and Home Assistant. As implemented in the `cloudflare/cloudflare-os` repository, these components act as secure, auditable intermediaries that translate natural language requests into authenticated API calls while maintaining strict user consent boundaries.

## Core Architecture: The Three Layers of Cloudflare OS Gatekeepers

The Gatekeeper system organizes access control into three distinct Durable Object layers, each defined in [`packages/workshop-shared/src/gatekeeper.ts`](https://github.com/cloudflare/cloudflare-os/blob/main/packages/workshop-shared/src/gatekeeper.ts).

### GatekeeperVendor: The Entry Point

The **GatekeeperVendor** serves as the durable-object entry point for service integration. It handles OAuth initialization, lists available resource types, and can auto-provision accounts. When the Workshop UI needs to display available connectors, it calls `GatekeeperVendor.describe()` to retrieve metadata including the vendor name, logo, and supported authentication flows.

### GatekeeperUser: Account Management

Once a user completes OAuth, the system instantiates a **GatekeeperUser** durable object representing that specific connected account. This layer surfaces account information, enumerates grantable resources via `getGatekeeperClassFor(url)`, and manages the credential lifecycle. Each connected Google or GitHub account maintains its own `GatekeeperUser` instance that persists the access tokens and refresh logic.

### Gatekeeper<Session>: Resource-Specific Access

The **Resource Gatekeeper** implements the `Gatekeeper<Session>` interface as a Durable Object facet bound to a specific resource URL—such as `https://docs.google.com/document/d/XYZ`. This layer exposes the concrete API methods (e.g., `listDocuments`, `sendEmail`) through a **session** RPC that gadgets invoke. Crucially, it routes all read operations through `ObservationAuthorizer.authorizeObservation()` and queues write operations in the `ApprovalQueue` for explicit user approval.

## Key Types and Interfaces Defined in gatekeeper.ts

The shared API contract in [`packages/workshop-shared/src/gatekeeper.ts`](https://github.com/cloudflare/cloudflare-os/blob/main/packages/workshop-shared/src/gatekeeper.ts) defines the metadata structures that enable type-safe integration:

- **VendorDescription**: UI metadata including the vendor name, logo URL, tagline, and a boolean flag indicating if the vendor supports sign-in capabilities.
- **AccountDescription**: Data structure representing a connected account in the UI, potentially declaring a singleton agent or management interface.
- **SupportedResource**: Declares resource types the vendor can bind, including URL patterns like `https://docs.google.com/*` for Google Docs.
- **ResourceDescription**: Metadata returned by resource-specific Gatekeepers containing the URL, title, suggested binding name, and TypeScript type definitions.
- **AgentCatalog**: A bounded discovery index that exposes reachable objects to the AI agent without requiring full session data retrieval.

## Runtime Lifecycle: How Gatekeepers Work in Practice

The execution flow follows a strict six-phase pattern enforced by the Overseer:

1. **Vendor discovery**: The Workshop UI calls `GatekeeperVendor.describe()` to enumerate available connectors.
2. **Account connection**: The UI invokes `GatekeeperVendor.connectAccount(callback, options)`, returning an OAuth URL. The callback's `complete(user, expiresAt)` method persists the `GatekeeperUser` after authorization.
3. **Resource selection**: The system may spawn a configurator iframe via `startResourceConfigurator` to capture the specific resource URL.
4. **Class resolution**: The Overseer calls `GatekeeperUser.getGatekeeperClassFor(url)` to retrieve the Durable Object class implementing `Gatekeeper<Session>` for that resource type.
5. **Session start**: The gadget invokes `Gatekeeper.startSession(approvalQueue)` to obtain a session stub providing the concrete API.
6. **Observations and actions**: Read operations pass through `ObservationAuthorizer.authorizeObservation()`, while writes are submitted via `approvalQueue.submitAction()` and only executed after user approval triggers `applyAction()`.

```typescript
// 1. List available vendors (UI side)
const vendors = await gatekeeperVendor.describe();

// 2. Connect a Google account (user clicks “Connect”)
const {url} = await gatekeeperVendor.connectAccount(callback, {scopes: "full"});
window.open(url, "_blank");

// 3. After OAuth completes, callback.complete(user) stores the account.
//    The Workshop now has a GatekeeperUser fetcher.

// 4. Resolve a specific resource (e.g. a Google Doc)
const {class: GatekeeperClass, resource} = await gatekeeperUser.getGatekeeperClassFor(
    "https://docs.google.com/document/d/XYZ");

// 5. Instantiate the resource Gatekeeper within the Overseer
const gatekeeper = ctx.facets.add(GatekeeperClass, { /* props with credentials */ });

// 6. Start a session for the gadget
const session = await gatekeeper.startSession(approvalQueue);

// 7. Read data (observation)
await observationAuthorizer.authorizeObservation({
  description: "Read document title",
  resourceId: resource.id,
});
const title = await session.getTitle();

// 8. Request a write (action)
const actionId = await session.createComment({text: "Hello"});
await approvalQueue.submitAction(actionId, {
  // ActionDescription describing the write
});

```

## Implementation Examples in the Cloudflare OS Repository

The `cloudflare/cloudflare-os` monorepo contains several reference implementations demonstrating the Gatekeeper pattern:

- **[`packages/gatekeeper-context/README.md`](https://github.com/cloudflare/cloudflare-os/blob/main/packages/gatekeeper-context/README.md)**: Implements a singleton agent providing a collections library and management UI.
- **[`packages/gatekeeper-mcp/README.md`](https://github.com/cloudflare/cloudflare-os/blob/main/packages/gatekeeper-mcp/README.md)**: Exposes a minimal "MCP" connector demonstrating the simplest possible Gatekeeper implementation.
- **[`packages/gatekeeper-google/README.md`](https://github.com/cloudflare/cloudflare-os/blob/main/packages/gatekeeper-google/README.md)**: Production-caliber OAuth integration for Google Workspace, showing real-world token management.
- **[`packages/gatekeeper-email/README.md`](https://github.com/cloudflare/cloudflare-os/blob/main/packages/gatekeeper-email/README.md)**: Demonstrates stateless email sending without persistent UI components.

## Summary

- Gatekeepers provide **capability-based security** for AI gadget integration with external APIs.
- The architecture separates concerns into **three Durable Object layers**: Vendor (service definition), User (account management), and Resource (concrete API access).
- All interactions are **audited and permissioned** through the `ObservationAuthorizer` for reads and the `ApprovalQueue` for writes.
- The core RPC contracts reside in **[`packages/workshop-shared/src/gatekeeper.ts`](https://github.com/cloudflare/cloudflare-os/blob/main/packages/workshop-shared/src/gatekeeper.ts)**.
- Concrete implementations follow a **six-phase lifecycle** from vendor discovery to action execution.

## Frequently Asked Questions

### What is the primary purpose of Gatekeepers in Cloudflare OS?

Gatekeepers serve as secure intermediaries that expose external services to AI-driven gadgets while enforcing user consent and maintaining audit trails. They prevent unauthorized access by requiring explicit approval for all write operations through the `ApprovalQueue`.

### How does the ApprovalQueue enforce security in Gatekeeper sessions?

When a gadget requests a write operation, the Resource Gatekeeper generates an action identifier and submits it to the `ApprovalQueue` rather than executing immediately. The Overseer only invokes `applyAction()` on the Gatekeeper after the user explicitly approves the operation in the Workshop UI, creating a mandatory authorization checkpoint for all state-changing operations.

### What distinguishes GatekeeperVendor from GatekeeperUser?

`GatekeeperVendor` is a singleton Durable Object that handles service-level concerns like OAuth flow initialization and resource type enumeration, while `GatekeeperUser` represents a specific authenticated instance of that service for one user, managing account-specific tokens and resolving resource URLs to concrete Gatekeeper classes.

### Where are the Gatekeeper interfaces defined in the source code?

The central RPC contracts defining `GatekeeperVendor`, `GatekeeperUser`, and `Gatekeeper<Session>` reside in **[`packages/workshop-shared/src/gatekeeper.ts`](https://github.com/cloudflare/cloudflare-os/blob/main/packages/workshop-shared/src/gatekeeper.ts)**, which also exports the shared type definitions including `VendorDescription`, `AccountDescription`, and `SupportedResource`.