Skip to content

Adapter Contract

Execution adapters are clients of Clasper Core. They are never peers and never trusted.

Adapters:

  • authenticate with scoped adapter tokens
  • request permission to execute (pre-execution decision)
  • enforce the granted scope (time/steps/cost/capabilities)
  • report telemetry back (ingest is mandatory)

All adapter calls use:

  • Header: X-Adapter-Token: <jwt>

The token is minted by your platform and must be scoped to:

  • adapter_id
  • tenant_id
  • workspace_id
  • allowed_capabilities[]

Clasper Core verifies tokens using ADAPTER_JWT_SECRET.

Adapters should register (and can be disabled at runtime):

  • POST /adapters/register

Example:

{
"adapter_id": "openclaw",
"display_name": "OpenClaw Executor",
"risk_class": "high",
"capabilities": ["browser", "filesystem.read"],
"version": "0.1.0",
"enabled": true,
"certification_tier": "community",
"tool_capabilities": {
"browser.navigate": ["browser"],
"browser.execute_js": ["browser"]
}
}
  • certification_tier (optional): verified | community | experimental — shown as a badge in the Ops Console.
  • tool_capabilities (optional): map of tool name → capability groups for tool-level scope.

Adapter requests permission:

  • POST /api/execution/request

Minimum fields:

  • execution_id (optional; generated if omitted)
  • adapter_id
  • tenant_id
  • workspace_id
  • requested_capabilities[]

Optional agent identity (for per-agent policies and budgets):

  • agent_id?: string — unique identifier for the agent (e.g. from multi-agent runtimes)
  • agent_role?: string — role label (e.g. assistant, researcher)
  • agent_metadata?: object — additional agent context

Optional execution context signals (recommended for high-risk capabilities like shell.exec):

  • intent?: string — human-readable declaration of why execution is requested (e.g. install_dependency, run_workspace_script)
  • context?: object — high-signal flags about likely side effects:
    • external_network?: boolean
    • writes_files?: boolean
    • elevated_privileges?: boolean
    • package_manager?: string (e.g. npm, pip, apt, brew)
    • targets?: string[] (e.g. domains/registries; optional)
  • provenance?: object — lightweight source metadata:
    • source?: "marketplace" | "internal" | "git" | "unknown"
    • publisher?: string
    • artifact_hash?: string

Notes:

  • These fields are declarative, not authoritative.
  • Missing fields are treated as unknown (they do not imply false).
  • Policy matching currently supports a subset of fields:
    • Supported: intent, context.external_network, context.writes_files, context.elevated_privileges, context.package_manager, provenance.source, provenance.publisher, and capability (matches against requested_capabilities[]).
    • Not matchable yet: context.targets and provenance.artifact_hash (captured for audit only).

Example request:

{
"execution_id": "exec_abc123",
"adapter_id": "openclaw",
"tenant_id": "t1",
"workspace_id": "w1",
"requested_capabilities": ["shell.exec"],
"intent": "install_dependency",
"context": {
"external_network": true,
"writes_files": true,
"package_manager": "npm",
"targets": ["registry.npmjs.org"]
},
"provenance": {
"source": "marketplace",
"publisher": "acme",
"artifact_hash": "sha256:..."
}
}

Decision response:

  • allowed: boolean
  • granted_scope (if allowed)
  • blocked_reason or requires_approval (if denied)
  • decision: "pending" + decision_id (if async approval required)

If allowed, adapter executes strictly within the granted scope:

  • capabilities[]
  • max_steps
  • max_cost
  • expires_at

Adapters must ingest telemetry after (and/or during) execution:

  • POST /api/ingest/trace
  • POST /api/ingest/audit
  • POST /api/ingest/cost
  • POST /api/ingest/metrics
  • POST /api/ingest/violations

All ingest payloads should be wrapped in a signed envelope:

{
"envelope_version": "v1",
"adapter_id": "openclaw",
"adapter_version": "0.4.1",
"issued_at": "2026-02-06T14:12:33Z",
"execution_id": "exec_abc123",
"trace_id": "trace_xyz789",
"payload_type": "trace",
"payload": { "...": "..." },
"payload_hash": "sha256:...",
"signature": "base64(...)"
}

Unsigned envelopes are accepted only in warn mode.

Before executing sensitive tools, adapters must request authorization:

POST /api/governance/tool/authorize

The response contains a short-lived JWT token. Adapters must include the token ID in telemetry for verification.

When Core returns a pending decision:

  1. Adapter pauses execution.
  2. Adapter polls:
    • GET /api/decisions/:id
  3. On approval, adapter consumes the decision token once:
    • POST /api/decisions/:id/consume
    • header: X-Decision-Token: <jwt>

Tokens are single-use and bound to (tenant_id, workspace_id, adapter_id, execution_id, decision_id).

All ingest payloads carry these identifiers:

  • tenant_id
  • workspace_id
  • execution_id
  • trace_id
  • adapter_id

Ingest endpoints are idempotent per (execution_id, event_type) to support retries.

See the canonical spec in the clasper-core repo:

  • contracts/adapter.openapi.yaml