# Build a Connector

A connector makes an existing product behave like an AIP participant without
moving that product's business logic into the protocol runtime.

A production connector is more than an HTTP client. It publishes an honest
capability contract, receives trusted execution context, maps provider errors,
supports recovery, and proves its behavior through the connector conformance
kit.

## 1. Start from the Product Boundary

Pin the exact upstream product revision, API version, or schema used by the
connector. Record:

- supported operations and provider identifiers;
- authentication and tenant model;
- idempotency and retry behavior;
- streaming and cancellation facilities;
- webhook signature and replay rules;
- transaction, reconciliation, and compensation behavior;
- provider rate, body-size, and timeout limits.

Do not design from marketing descriptions. Connector contracts must follow the
real API and code boundary.

## 2. Choose Connector Roles

The SDK separates product roles:

| Trait | Responsibility |
|---|---|
| `Connector` | Identity, discovery, readiness, and error mapping |
| `CapabilityProviderConnector` | Publish executable capabilities |
| `InboundConnector` | Convert provider events into AIP envelopes |
| `ChannelConnector` | Ingest and emit conversation-channel traffic |
| `OutboundConnector` | Legacy outbound invocation boundary |
| `FrozenConnector` | Production invocation under trusted execution context |
| `EscalationConnector` | Map human escalation to the product |

New production connectors should implement `FrozenConnector` for callable
capabilities. Its default optional operations fail explicitly, so a connector
cannot accidentally advertise cancellation, commit, or reconciliation that it
does not implement.

## 3. Publish Honest Capabilities

For every capability:

1. Define strict input and output JSON Schemas.
2. Declare every side effect and data classification.
3. Match sync, async, streaming, cancellation, and retry flags to real code.
4. Describe provider idempotency exactly.
5. Add credential, approval, transaction, and compensation contracts where
   required.
6. Mark experimental or deprecated behavior explicitly.

Gateway admission is atomic: every advertised callable capability needs a
concrete handler with matching implementation support.

## 4. Use Trusted Execution Context

`FrozenConnector::invoke_typed` receives `ActionExecutionContext`. This context
contains the transport-authenticated actor, verified tenant, deadline,
cancellation token, trace information, transaction state, stream publisher, and
resolved credential reference.

Use it as the authority source. Never reconstruct tenant, approver, or actor
identity from action input or free-form metadata.

## 5. Keep Secrets at the Final Boundary

Use `ConnectorSecret` for in-memory secret bytes. It is non-serializable,
redacted in diagnostics, compared in constant time, and zeroized on drop.

Production configuration should load secrets from owner-only files, a secret
manager, or a workload credential provider. Protocol objects carry only opaque
references and sanitized lifecycle metadata.

## 6. Normalize Failures

Return `ConnectorFailure` with:

- a stable namespaced code;
- a redacted human-readable message;
- the AIP error category;
- retry safety and optional backoff;
- provider request and operation ids;
- remote status;
- `uncertain_outcome` when a side effect may have occurred;
- redacted structured details;
- source component and failed operation.

Do not convert every provider error into a generic retryable failure. In
particular, an uncertain commit must enter reconciliation instead of automatic
retry.

## 7. Implement Lifecycle Operations

Implement only the operations the capability advertises:

- `invoke_typed` for normal execution;
- `plan_typed` for dry-run and plan;
- `commit_typed` for plan commit;
- `compensate_typed` for governed compensation;
- `cancel_typed` for provider cancellation;
- `reconcile_typed` for uncertain outcomes;
- `emit_typed` and `ingest_typed` for provider events and results.

Stream incremental output through the execution context's publisher rather than
buffering the entire provider stream into a final result.

## 8. Secure Webhooks

Webhook ingress should verify the raw body before JSON parsing. Validate the
signature, timestamp skew, subscription or tenant binding, delivery id, and body
size. Claim the delivery id durably before acknowledgement and map it to AIP
idempotency.

Outbound webhook registration must restrict targets to deployment-owned HTTPS
prefixes or an equivalent allowlist. Do not accept arbitrary callback URLs from
action input.

## 9. Add Evidence, Not Only Unit Tests

A complete connector qualification includes:

- contract and mapping unit tests;
- frozen conformance tests for every advertised behavior;
- malformed input and provider error tests;
- cancellation and streaming tests;
- idempotency collision and replay tests;
- approval and transaction tests when advertised;
- webhook signature, skew, and replay tests;
- restart recovery and uncertain-outcome reconciliation;
- isolated-live execution against the pinned upstream product;
- retained, secret-free evidence tied to source and image digests.

Use the [Cal.diy Connector](../connectors/cal-diy.md) and its
[isolated-live evidence](../testing/cal-diy-isolated-live.md) as a reference for
separating deterministic conformance from isolated-live qualification.

## Definition of Complete

A connector is complete only when its manifest, implementation, tests, live
provider behavior, and retained evidence agree. A passing mock, a successful
health check, or the presence of a capability in a manifest proves only one part
of that contract.
