Cloudflare · Capability

Cloudflare Agent Onboarding (Edge-Native)

Cloudflare Agent Onboarding — the edge-is-the-gateway pattern. Unlike every other adapter in this series which sits behind a Cloudflare Worker, the Cloudflare adapter IS the Worker. Mints scoped Cloudflare API Tokens at the edge with no origin round-trip; uses Workers KV for the operator key-directory cache; emits audit via Logpush for delivery into the customer's existing log pipeline (Datadog, Splunk, S3, etc.). Runtime policy enforcement (signature verify, consent check, scope classify, audit emit) lives in the orchestration.steps below — each step that gates issuance carries on_failure: deny. Lint-time validation of this capability shape lives in the companion Polychro ruleset at https://github.com/api-evangelist/posts/blob/main/polychro/agent-onboarding-rules.yaml — Polychro is Naftiko's governance layer, separate from the capability spec, and is the correct home for cross-object consistency rules that apply across every agent-onboarding capability.

Run with Naftiko CloudflareCloudflare WorkersCloudflare API TokensCloudflare AI GatewayWorkers KVLogpushR2Agent OnboardingEdge ComputeNaftiko Capability

What You Can Do

POST
Onboardagent
/v1/agents/onboard
POST
Revokeagent
/v1/agents/{agent_id}/revoke

MCP Tools

agent-register

agent-revoke

idempotent

Capability Spec

cloudflare-agent-onboarding.yaml Raw ↑
naftiko: 1.0.0-alpha2
info:
  label: Cloudflare Agent Onboarding (Edge-Native)
  description: 'Cloudflare Agent Onboarding — the edge-is-the-gateway pattern. Unlike every
    other adapter in this series which sits behind a Cloudflare Worker, the Cloudflare adapter
    IS the Worker. Mints scoped Cloudflare API Tokens at the edge with no origin round-trip;
    uses Workers KV for the operator key-directory cache; emits audit via Logpush for delivery
    into the customer''s existing log pipeline (Datadog, Splunk, S3, etc.). Runtime policy enforcement (signature verify, consent check, scope classify, audit emit) lives in the orchestration.steps below — each step that gates issuance carries on_failure: deny. Lint-time validation of this capability shape lives in the companion Polychro ruleset at https://github.com/api-evangelist/posts/blob/main/polychro/agent-onboarding-rules.yaml — Polychro is Naftiko''s governance layer, separate from the capability spec, and is the correct home for cross-object consistency rules that apply across every agent-onboarding capability.'
  tags:
  - Cloudflare
  - Cloudflare Workers
  - Cloudflare API Tokens
  - Cloudflare AI Gateway
  - Workers KV
  - Logpush
  - R2
  - Agent Onboarding
  - Edge Compute
  - Naftiko Capability
  created: '2026-05-28'
  modified: '2026-05-28'
  related:
  - https://apievangelist.com/2026/05/27/automated-agent-onboarding-is-a-naftiko-capability-not-a-gateway-feature/
  - https://github.com/api-evangelist/cloudflare
binds:
- namespace: env
  keys:
    CLOUDFLARE_ACCOUNT_ID: CLOUDFLARE_ACCOUNT_ID
    CLOUDFLARE_API_TOKEN: CLOUDFLARE_API_TOKEN
    CLOUDFLARE_AUDIT_BUCKET: CLOUDFLARE_AUDIT_BUCKET
    CLOUDFLARE_KV_NAMESPACE: CLOUDFLARE_KV_NAMESPACE
    AGENT_TRUSTED_ISSUERS: AGENT_TRUSTED_ISSUERS
    AGENT_CONSENT_HASH: AGENT_CONSENT_HASH
capability:
  consumes:
  - type: http
    namespace: cloudflare-api
    baseUri: https://api.cloudflare.com/client/v4
    description: Cloudflare API — Token issuance + revocation + AI Gateway access + R2 audit
      writes. All operations targeted by the Worker; no separate origin.
    resources:
    - name: account-tokens
      path: /accounts/{account_id}/tokens
      operations:
      - name: createtoken
        method: POST
        description: Create a scoped Cloudflare API Token. The token's permissions specify
          which Cloudflare resources the agent can call; quota and rate-limit hit Workers
          rate-limiting bindings, not the token itself.
        outputRawFormat: json
        outputParameters:
        - { name: result, type: object, value: $. }
        inputParameters:
        - { name: account_id, in: path, type: string, required: true }
        - { name: body, in: body, type: object, required: true }
      - name: deletetoken
        method: DELETE
        description: Revoke a previously-issued token.
        outputRawFormat: json
        outputParameters:
        - { name: result, type: object, value: $. }
    - name: ai-gateway-logs
      path: /accounts/{account_id}/ai-gateway/gateways/{gateway_id}/logs
      operations:
      - name: queryaigatewaylogs
        method: GET
        description: For agents calling LLMs through Cloudflare's AI Gateway — the
          observability surface that captures originating request signatures alongside
          model usage.
        outputRawFormat: json
        outputParameters:
        - { name: result, type: object, value: $. }
    - name: r2-audit-objects
      path: /accounts/{account_id}/r2/buckets/{bucket_name}/objects/{object_key}
      operations:
      - name: putauditobject
        method: PUT
        description: Write a structured agent-onboarding audit event to R2. The customer's
          Logpush destinations pick this up via R2 event notifications.
        outputRawFormat: json
        outputParameters:
        - { name: result, type: object, value: $. }
        inputParameters:
        - { name: bucket_name, in: path, type: string, required: true }
        - { name: object_key, in: path, type: string, required: true }
        - { name: body, in: body, type: object, required: true }
    authentication:
      type: bearer
      token: '{{env.CLOUDFLARE_API_TOKEN}}'
  - type: workers-kv
    namespace: cloudflare-kv
    description: Workers KV namespace caching operator key directories (e.g.
      anthropic.com/.well-known/web-bot-keys/) with TTL. Revoking a trusted issuer is one
      KV write; propagates globally in ~60s.
    binding: AGENT_TRUST_CACHE
    operations:
    - name: getkey
      description: Read cached operator key bundle.
    - name: putkey
      description: Write/update operator key bundle.
  orchestration:
  - name: onboard-agent
    description: All steps execute at the edge in one Worker invocation — no round-trip
      to an origin gateway. Verify Web Bot Auth signature against KV-cached operator keys,
      classify scopes against the Worker-bound policy, mint a Cloudflare API Token with
      precise permission scope, write audit to R2, return credential.
    inputs:
    - { name: signature, type: object, required: true }
    - { name: signature_agent, type: string, required: true }
    - { name: skill_id, type: string, required: true }
    - { name: requested_scopes, type: array, required: true }
    - { name: consent_hash, type: string, required: true }
    - { name: contact, type: object, required: true }
    steps:
    - id: load_operator_keys
      type: builtin.kv.get
      description: Fetch the operator's key directory from Workers KV; if missing or
        expired, fetch upstream and cache.
      with:
        binding: AGENT_TRUST_CACHE
        key: 'keys:${input.signature_agent}'
        fallback_fetch: 'https://${input.signature_agent}/.well-known/web-bot-keys/'
        ttl_seconds: 3600
    - id: verify_signature
      type: builtin.web-bot-auth.verify
      with:
        signature: '${input.signature}'
        agent: '${input.signature_agent}'
        keys: '${steps.load_operator_keys.keys}'
        trusted_issuers: '{{env.AGENT_TRUSTED_ISSUERS}}'
      on_failure: deny
    - id: verify_consent
      type: builtin.policy.assert
      with:
        assert: '${input.consent_hash} == {{env.AGENT_CONSENT_HASH}}'
      on_failure: deny
    - id: classify_scopes
      type: builtin.policy.scope-classify
      with:
        requested: '${input.requested_scopes}'
    - id: mint_token
      call: cloudflare-api.createtoken
      description: Mint a Cloudflare API Token with permission groups derived from
        the scope tier. The token value is returned to the agent exactly once.
      with:
        account_id: '{{env.CLOUDFLARE_ACCOUNT_ID}}'
        body:
          name: 'agent-${steps.verify_signature.agent_id}'
          policies:
          - effect: allow
            permission_groups: '${steps.classify_scopes.cloudflare_permission_groups}'
            resources:
              'com.cloudflare.api.account.${env.CLOUDFLARE_ACCOUNT_ID}': '*'
          not_before: '${now.iso}'
          expires_on: '${now.plus_days(30).iso}'
          condition:
            request.ip:
              in: '${input.contact.allowed_ip_ranges}'
              not_in: []
    - id: emit_audit
      call: cloudflare-api.putauditobject
      description: Write the structured audit event to the R2 audit bucket. Customer
        Logpush destinations (Datadog/Splunk/S3/GCS/Sumo/Mezmo/New Relic) receive it
        automatically through their standard pipelines.
      with:
        account_id: '{{env.CLOUDFLARE_ACCOUNT_ID}}'
        bucket_name: '{{env.CLOUDFLARE_AUDIT_BUCKET}}'
        object_key: 'agent-onboarded/${now.year}/${now.month}/${now.day}/${steps.verify_signature.agent_id}-${now.epoch_ms}.json'
        body:
          event_type: agent.onboarded
          agent_id: '${steps.verify_signature.agent_id}'
          operator: '${input.contact.operator}'
          support_url: '${input.contact.support_url}'
          purpose: '${input.contact.purpose}'
          skill_id: '${input.skill_id}'
          scope_tier: '${steps.classify_scopes.target}'
          permission_groups: '${steps.classify_scopes.cloudflare_permission_groups}'
          consent_hash: '${input.consent_hash}'
          signature_keyid: '${steps.verify_signature.keyid}'
          token_id: '${steps.mint_token.id}'
          token_expires_on: '${steps.mint_token.expires_on}'
    output:
      agent_id: '${steps.verify_signature.agent_id}'
      token_id: '${steps.mint_token.id}'
      credential:
        type: Bearer
        header: Authorization
        value: '${steps.mint_token.value}'
        expires_on: '${steps.mint_token.expires_on}'
        revocation_url: '/v1/agents/${steps.verify_signature.agent_id}/revoke'
      scope_tier: '${steps.classify_scopes.target}'
      permission_groups: '${steps.classify_scopes.cloudflare_permission_groups}'
  - name: revoke-agent
    description: Delete the API Token; propagates globally within Cloudflare's edge in seconds.
    inputs:
    - { name: token_id, type: string, required: true }
    steps:
    - id: delete_token
      call: cloudflare-api.deletetoken
      with:
        account_id: '{{env.CLOUDFLARE_ACCOUNT_ID}}'
        body:
          token_id: '${input.token_id}'
    output:
      revoked: true
  exposes:
  - type: rest
    namespace: cloudflare-agent-onboarding-rest
    port: 8080
    description: REST surface — but in the Cloudflare adapter the REST surface IS the
      Worker route, not an origin endpoint. Deployment is wrangler-driven.
    resources:
    - path: /v1/agents/onboard
      operations:
      - { method: POST, name: onboardagent, call: orchestration.onboard-agent }
    - path: /v1/agents/{agent_id}/revoke
      operations:
      - { method: POST, name: revokeagent, call: orchestration.revoke-agent }
  - type: mcp
    namespace: cloudflare-agent-onboarding-mcp
    port: 9090
    transport: http
    tools:
    - name: agent-register
      hints: { readOnly: false, destructive: false, idempotent: false }
      call: orchestration.onboard-agent
    - name: agent-revoke
      hints: { readOnly: false, destructive: true, idempotent: true }
      call: orchestration.revoke-agent
  - type: agent-skill
    namespace: cloudflare-agent-onboarding-skill
    description: 'Agent skill at /skills/onboard-agent.md. Cloudflare-specific addendum:
      the credential issued is a Cloudflare API Token with precisely-scoped permission
      groups; the agent can call any Cloudflare API surface (Workers, R2, KV, AI Gateway,
      D1, etc.) within those permissions, gated by the token''s condition block.'
    skill:
      name: onboard-agent
      file: skills/onboard-agent.md