← Diagram index

RFC-0001: Provider Egress and Credential Custody Options

Status: Proposed Author: Roberto Garcia Navarro Date: 2026-10-03

Problem

TAP rooms use personal and workspace provider credentials. A turn needs one approved credential without exposing vendor material to room members, AgentSessionDO, or ze-harness. Standalone ze-harness must retain direct provider support.

Target contract

ze-harness composes ProviderDefinition and ModelService. TAP injects a Gateway provider definition; standalone hosts use direct provider definitions.

declare const valueObject: unique symbol;
type ValueObject<Value, Kind extends string> = Value & {
  readonly [valueObject]: Kind;
};

type CredentialBindingId = ValueObject<string, 'CredentialBindingId'>;
type TurnEgressLease = ValueObject<string, 'TurnEgressLease'>;

interface GatewayTurnControlPort {
  admitTurn(input: {
    roomId: RoomId;
    turnId: TurnId;
    bindingId: CredentialBindingId;
  }): Promise<TurnEgressLease>;
}

interface GatewayInvocationPort {
  stream(input: {
    lease: TurnEgressLease;
    call: ModelCallIdentity;
    request: ModelRequest;
    signal: AbortSignal;
  }): Stream.Stream<ModelEvent, ModelFailure>;
}

CredentialBinding stays in Custody. The room coordinator stores the opaque lease in memory for its turn. GatewayProviderDefinition reads that lease at ModelService.stream, then calls GatewayInvocationPort. It never uses ProviderCredentialPort or receives vendor material.

Gateway maps each lease and ModelCallIdentity to one internal invocation grant. turnId, logicalCallId, and attemptId identify the invocation for deduplication. This covers tool continuations and retries within one turn.

Option A: Cloudflare-native Gateway egress

flowchart LR Room[Room coordinator] -->|binding ID + turn ID| Gateway[Gateway control + egress\nCloudflare Worker] Gateway -->|memory-only turn lease| Room Room -->|turn lease| Harness[ze-harness\nGatewayProviderDefinition] Harness -->|call identity + lease| Gateway Gateway -->|authorize + decrypt| Vault[(D1 credential vault)] Gateway -->|vendor request| Provider[Provider] Provider -->|stream| Gateway --> Harness
Open the interactive diagram

Gateway player: the Cloudflare Worker. It owns turn admission, D1 credential resolution, and provider egress. D1 stores ciphertext and delegation metadata; a Cloudflare secret-backed application key protects the records.

Fit: one operational boundary. Limit: Cloudflare owns custody and key policy; a later AWS move requires storage and crypto migration.

Option B: AWS custody-first Gateway egress

flowchart LR Room[Room coordinator] -->|binding ID + turn ID| Egress[Gateway control + egress\nAWS custody service] Egress -->|memory-only turn lease| Room Room -->|turn lease| Harness[ze-harness\nGatewayProviderDefinition] Harness -->|call identity + lease| Egress Egress -->|ciphertext records| Vault[(DynamoDB credential vault)] Egress -->|branch-key lookup| KeyStore[(DynamoDB key store)] KeyStore -->|decrypt branch material| KMS[AWS KMS root key] Egress -->|vendor request| Provider[Provider] Provider -->|stream| Egress --> Harness
Open the interactive diagram

Gateway player: AWS Custody. It accepts ze-harness calls, redeems grants, resolves credentials, and calls providers. Cloudflare only admits turns and returns leases. Vendor material never returns to Cloudflare or ze-harness.

The hierarchical keyring uses one KMS root per environment and region, DynamoDB branch keys, and a bounded local cache of branch material. It creates a unique data key per encrypted credential record.

DynamoDB model

Egress reads by CredentialBindingId. Grants, turns, and delegation policy remain Gateway-control state. Branch keys use account:<id> or workspace:<id>, never room or request IDs. Encryption context binds tenant, credential reference, provider, and revision.

Cache and access rules

Fit: independent custody and KMS policy. Limit: AWS service ownership, DynamoDB operations, key-cache controls, and vault migration.

Comparison

Concern Option A Option B
Gateway Cloudflare Worker AWS custody service
Vault D1 DynamoDB plus key store
Root key Cloudflare secret-backed key AWS KMS root
Key cache Application-defined Hierarchical keyring
Fit Fastest path Long-term custody

Direction

Prefer Option B. Gateway calls providers, Custody owns vendor material, and TAP uses a Gateway ProviderDefinition.

Current branch gaps

Acceptance criteria

References