guides
Intended Documentation
Connector SDK
Build a fail-closed connector by extending BaseAdapter from @intended/connector-sdk. The base class verifies the Authority Token — signature, tenant, adapter, expiry, single-use nonce — before your action code ever runs.
Connector SDK#
A connector (adapter) is the last line of defense: it is the component that actually performs an approved action against a downstream system, and it refuses to act unless the Authority Token verifies. You build one by extending BaseAdapter from @intended/connector-sdk and implementing a single method, executeAction. The base class does the security-critical work — token verification with kid pinning, tenant/adapter/target binding, expiry, and single-use nonce consumption — and it is fail-closed: if any check fails, your executeAction is never called.
Warning
Do not implement your own execute() or skip the base-class validate(). BaseAdapter.execute() always validates the token first and returns a rejected result on any failure, before touching the downstream system. That is the guarantee the connector model rests on.
Note
This is a different thing from @intended/adapters (the LangChain / Semantic Kernel / CrewAI / AutoGen packages). Those map an agent framework's actions into intents on the way in. The connector SDK described here runs after a decision, verifying the issued token before executing. Don't conflate the two.
The validation pipeline#
When the runtime dispatches an approved action, it hands your adapter a ConnectorEnvelope containing the authorityToken. BaseAdapter.execute() runs this pipeline before any action logic:
Parse the envelope
The envelope is validated against ConnectorEnvelopeSchema (tenantId, correlationId, intentId, action, adapterId, adapterTarget, authorityToken, optional payload / resource).
Decode kid and fetch the tenant public key
The token header is decoded, and the tenant's public key for that kid is fetched (getAuthorityPublicKeyByKid). An unknown kid fails closed.
Verify the Ed25519 signature with the kid pinned
verifyAuthorityDecisionToken checks the signature against the pinned key id.
Bind the claims
Assert the token's tenantId, adapterId, and adapterTarget match the envelope, and that decision === "APPROVED". Mismatches throw TOKEN_TENANT_MISMATCH, TOKEN_ADAPTER_MISMATCH, TOKEN_ADAPTER_TARGET_MISMATCH, or TOKEN_DECISION_INVALID.
Check expiry
A token past expiresAt throws TOKEN_EXPIRED.
Consume the nonce (single use)
consumeAuthorityTokenNonce atomically consumes the per-tenant nonce. A replay whose nonce is already consumed is rejected. Only now is executeAction called.
Validation runs before execution. Any failed check returns a rejected ExecutionResult and the downstream system is never touched.
Build a connector#
Extend BaseAdapter, provide a _manifest, and implement executeAction. The base class hands you the already-validated claims, so your code only contains system-specific logic.
Manifest fields (ConnectorManifestSchema)#
| Field | Type | Notes |
|---|---|---|
id | string | Unique adapter id; the token's adapterId must equal this. |
name | string | Display name. |
version | string | Semantic version. |
description | string | One line. |
capabilities | string[] | ≥1 action patterns, each {system}.{entity}.{verb} (lowercase, hyphens). |
supportedAuthMethods | array | Subset of oauth2, api-token, github-app, pat. |
status | "active" | "scaffolded" |
Envelope fields (ConnectorEnvelopeSchema)#
| Field | Type | Notes |
|---|---|---|
tenantId | string | Must match the token. |
correlationId | uuid | Ties to the audit chain. |
intentId | uuid | The originating intent. |
action | string | The action being executed. |
adapterId | string | Must equal the manifest id and the token adapterId. |
adapterTarget | string | Must equal the token adapterTarget. |
authorityToken | string | The Ed25519 JWT from POST /intent. |
payload / resource | object | Optional; your action inputs. |
Register the connector#
Register adapters in an AdapterRegistry. The registry refuses to silently overwrite an existing id and is what the execution engine looks up by adapterId.
AdapterRegistry also exposes get, listIds, listManifests, testConnection(adapterId, tenantId), and testAllConnections(tenantId).
Execution outcomes#
executeAction returns an ExecutionResult. The base class also synthesizes one on a failed validation or a thrown error.
status | When | Meaning |
|---|---|---|
executed | Your executeAction succeeded. | The downstream action was performed. |
rejected | Token validation failed, or executeAction threw. | Nothing was executed; reason carries the code. |
skipped | Your executeAction chose not to act. | A deliberate no-op you returned. |
Validation-failure reasons surfaced as reason on a rejected result include TOKEN_TENANT_MISMATCH, TOKEN_ADAPTER_MISMATCH, TOKEN_ADAPTER_TARGET_MISMATCH, TOKEN_DECISION_INVALID, TOKEN_EXPIRED, and the nonce-replay reason returned by consumeAuthorityTokenNonce. A thrown executeAction is caught and returned as rejected rather than propagating — the connector never half-executes on an error.
testConnection
BaseAdapter provides a default testConnection that reports the adapter as reachable. Override it with a real health check against your downstream system:
Next steps#
- Verify Decision Tokens — the verification the base class performs.
- Enforcement SDK — drive intents and verification from your app.
- Error Patterns — runtime error codes and remediation. </content>