Adapters
Adapters define how Cessy calls external services. They keep endpoint, auth, credential, and request behavior out of ad hoc policy code.
Use adapters for
- calling external APIs after modeled events
- sending data to integration services
- fetching external state needed by controlled workflows
- centralizing credentials and auth behavior
- making policy side effects inspectable
Do not use adapters for
- public app API contracts
- bypassing commands
- hiding business decisions outside the event model
- arbitrary frontend calls with user-provided secrets
External consumers should call generated runtime APIs, webhooks, subscriptions, or a BFF.
Auth and credentials
Store credentials in configured credential surfaces, not in page bundles, docs, prompts, or custom code strings. Name the target environment when testing adapter behavior.
Policy code calls adapters through ctx.adapters. Cessy resolves and injects adapter authentication server-side, so Workspace E2E tests do not require injecting a public runtime API key into the policy worker just to call an adapter. Named Credential Store records used by session_token and Custom Page principal assertions are selected for the active Production or Workspace runtime source; static adapter secrets are not source-scoped.
Static bearer, basic, api-key, and oauth_client_credentials secrets are encrypted before persistence on the server-side adapter record. They are not embedded in browser/page code or returned by adapter read surfaces. These auth types do not automatically bind named Credential Store records: creating LIGHTRAG_API_KEY, for example, does not attach it to an api-key adapter. Use update_adapter to rotate the protected adapter secret.
Use inspect_adapter_credentials to verify provenance. Its schemaVersion: 2 receipt reports static auth as storage: "protected_adapter_secret" and sourceScoped: false, which distinguishes protected server-side adapter storage from plaintext inline configuration, and returns no secret fields. Malformed stored auth reports storage: "unknown" instead of claiming unverified protection. For session_token, the tool shows which named, source-scoped Credential Store records the adapter would use in Production or a Workspace. That receipt contains names, resolution status, selected source scopes, update times, and opaque encrypted-revision fingerprints only. It never returns credential values or encrypted envelopes. Authorization-code OAuth reports oauth_connection: provider access tokens live on the connection record, while the adapter client secret remains encrypted at rest on the server-side adapter record.
Signed Custom Page principals
An exposed named operation can authenticate the current Custom Page principal to its downstream service without trusting browser input:
Those three values are the complete builder contract. Cessy owns the fixed X-CES-Principal-Assertion header and mints a new compact JWT for every actual outbound attempt after authenticating the Page principal and authorizing the operation. The protected header is exactly alg: HS256, typ: ces-principal-assertion+jwt, and the configured kid. The token expires after 60 seconds, is limited to 8 KiB, and binds sub to the server principal plus the deployment issuer, audience, tenant, app, runtime source, adapter, and operation. Browser identity, roles, attributes, groups, tags, request data, and other PII are not claims.
The header is server-owned. Caller headers, adapter defaults, auth-header configuration, raw adapter calls, Runtime MCP, policies, and other surfaces cannot create or override it in any capitalization. A signing or credential error stops before downstream I/O, redirect handling cannot forward it to another origin, and Cessy masks the assertion from captures, diagnostics, and the browser response.
The verifier must require TLS and fail closed: accept exactly one bounded header, require the fixed algorithm and type, select only an expected kid, and verify signature, issuer, exact audience, iat, exp, jti, version, and all signed request-context claims. Use only the verified sub as identity. Never fall back to a principalId, group, role, or tag from browser-controlled body, path, query, or headers. Missing, malformed, expired, duplicated, oversized, or wrongly scoped assertions deny the request.
HS256 makes every holder of the shared secret a co-signer. Use at least 32 random bytes, isolate one key per adapter trust domain/audience and environment, and provision it only to Cessy and that verifier. keyId is a non-secret rotation label, not a key or permission. Never reuse the signing key as an adapter API key or Runtime API key.
Multiple adapter authRules are OR-combined. If role and attribute checks must both pass, put them in one expression, for example "'knowledge-user' in $principal.roles && $principal.attr.suspended != true".
Inspect and change endpoint schemas safely
list_adapter_endpoints is a redacted troubleshooting summary. It tells you
whether request and response schemas exist, but it intentionally does not return
their contents. Never infer an unseen schema and replace it.
Before editing an endpoint, call get_adapter_endpoint with the app, adapter,
and operation IDs. The result contains the complete non-secret endpoint
definition and a deterministic revision. Pass that value as
expectedRevision to update_adapter_endpoint. If another writer changed the
endpoint since inspection, Cessy rejects the update without writing; inspect it
again before deciding how to proceed.
Omitted fields remain unchanged. Use null to remove an optional
pathParams, bodySchema, responseSchema, description, or exposure
field. A successful fenced update returns the exact before/after definitions and
a restore object. To undo the update, call update_adapter_endpoint again
with the restore object’s expectedRevision and patch fields. This reversal is
also conflict-checked and recorded as an endpoint update.
Request schemas govern browser-provided business input only. Do not add a
principal, roles, groups, or tags to a Page request body as an authorization
workaround. For authenticated Custom Pages, identity continues to come only
from the server session and signed principal assertion described above.
If the downstream needs fine-grained tags, keep them in an app-owned EffectiveKnowledgeAccess projection keyed by principal ID. After verification, use only sub to call the existing exact Runtime projection-document endpoint with a dedicated least-privileged Runtime API key. Missing, inactive, malformed, or empty access denies; browser-provided IDs or tags are never a fallback. See Permissions and Build Custom Pages for the pull pattern and tampering test.
Session-token cache control
Session tokens have no independent cache TTL. A cached token remains in use until the configured expiry response triggers refresh, adapter auth or base URL changes, an operator explicitly invalidates the session, or the process exits. Runtime materialization expiry by itself does not evict the token.
Use invalidate_adapter_session for one adapter and one Production or Workspace source. It makes no upstream request. Cessy records a durable source generation and evicts the matching local token when the event is observed, forcing later materializations in every process onto a fresh login. A request already in flight when the receipt is issued may still finish with its old token.
Verification
Use test_adapter with a named, parameterless GET or HEAD operation to verify connectivity. When no operation is supplied, Cessy prefers a safe operation named healthCheck, then the first safe read operation. It never selects a mutating operation or invents a request to the base URL. An explicit unknown, mutating, parameterized, risk-declared, or approval-requiring operation is rejected before authentication or adapter I/O. If no safe read operation exists, Cessy resolves credentials and authentication settings without a business request and reports connectivity as inconclusive. Only session-token authentication performs a remote login in that mode.
sourceScope accepts exactly production (the default), workspace:<workspaceId>, or legacy *. Cessy checks that a Workspace belongs to the app before login or adapter I/O. Production and Workspace tests report sourceBinding: runtime; this describes the selected runtime credential/source context. The probe uses the active base runtime adapter configuration, not an unpromoted Workspace draft. The * scope reports sourceBinding: global_credentials_only: it selects globally scoped credentials and is not an exact runtime binding for Production or a Workspace.
The result identifies the operation, method, redacted structural path shape, execution phase, httpResponseReached, elapsed time, terminal attempts, retryDecision and refreshDecision evidence when available, sourceBinding, and an opaque runtimeFingerprint. At result level, httpResponseReached is true when any login or safe-probe leg reached response headers, even if a later retry failed before its response. The fingerprint is a sha256: value used for equality comparisons; it does not reveal deployment metadata. Literal path segments are masked. POST, PUT, PATCH, and DELETE operations are not available through the connectivity test.
Adapter failures and non-success HTTP responses add bounded, redacted diagnostics to the policy execution. Each entry can include adapter and operation identity, phase, method and structural path shape, status, attempts, optional elapsedMs, retryDecision, refreshDecision, httpResponseReached, transportCategory, an optional allowlisted transportCode, runtime source, and runtimeFingerprint. httpResponseReached: true means that at least response headers arrived; false distinguishes a pre-HTTP transport failure. Older evidence can report this field as unknown. A receipt retains at most 16 chronological entries while preserving the terminal evidence.
The finite transport categories and allowlisted low-level codes are:
Unrecognized codes are omitted rather than copied into evidence. Unknown ERR_TLS_* and ERR_SSL_* families may still map to tls_handshake without retaining the raw code. Read the recorded retryDecision (not_triggered, retried, or exhausted), refreshDecision (not_applicable, not_triggered, refreshed, or refresh_failed), and retriable flag instead of inferring retry behavior from a category.
This evidence is retained even if policy code handles the response and the policy completes successfully. Inspect the affected policy execution through get_execution; it validates app ownership, re-normalizes stored diagnostics at read time, and omits free-form upstream summaries plus adjacent free-form policy and correlated execution context whenever an adapter receipt is present. Share only its normalized adapterDiagnostics subsection as the adapter receipt. get_error_context can also contain raw input data, policy source, stack traces, and details, so its full output is not a safe-share receipt. Credential values, auth headers, cookies, literal path segments, hostnames, query strings, full upstream URLs, arbitrary error codes, and nested causes are not rendered in normalized adapter diagnostics.
Safe troubleshooting workflow
Use Cessy’s allowlisted diagnostic surfaces in this order:
- Call
list_adapterswith the app ID, thenlist_adapter_endpointswith the app ID and adapter name. Useget_adapter_endpointonly when you need the exact authoring configuration for one operation; treat that detail as app configuration rather than a generally shareable diagnostic receipt. - Call
inspect_adapter_credentialswith the app ID and adapter name. - Call
test_adapterwith the app ID, adapter name,sourceScope: "production", and an explicit safe GET/HEAD operation ID. Useworkspace:<workspaceId>for an exact Workspace binding. Reserve legacy*for global-credential troubleshooting; it is not an exact runtime test. - For a separate policy call that exhibits the problem, call
get_executionwith the app ID and that affected execution or correlation ID. Share only the normalizedadapterDiagnosticssubsection; literal paths are shaped again at read time, and upstream summaries plus adjacent free-form policy and correlated execution context are omitted whenever an adapter receipt is present.
For a Workspace, pass workspaceId to inspect_adapter_credentials and get_execution, and pass sourceScope: "workspace:<workspace-id>" to test_adapter. If a policy also creates an Error Log entry, get_error_context can help interactive debugging, but review it as sensitive and do not share its full output.
The list tools return allowlisted summaries: authentication/default-header values, free-form descriptions, parameter names, and auth rules are omitted; URL hosts and literal path segments are masked; only scheme, non-default port, path depth, normalized {param} markers, and bounded exposure flags remain. Adapter and operation identifiers remain visible for correlation, so never embed credential material in an identifier. Do not replace these receipts with unformatted docker inspect, docker exec ... env or printenv, resolved docker compose config, environment-file output, raw credential rows, auth headers/cookies, or token-bearing URLs. Those outputs can put live credentials into terminals, logs, and transcripts before redaction. If that happens, rotate or revoke the exposed material immediately; for session_token, also invalidate the affected source-scoped session.