> ## Documentation Index
> Fetch the complete documentation index at: https://actelos.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Writing a Custom Adapter Module

> Skeleton and example for building a custom adapter

This page covers the adapter-specific parts of writing a custom module.
For the shared mechanics (file layout, registration, lifecycle) see
[Writing a custom module](/cyrnel/specs/writing-custom-modules). For the full
interface reference see [`AdapterModule`](/cyrnel/specs/adapter-module).

## Minimal Skeleton

```ts theme={null}
import type { AdapterModule, InvokeInput, ModuleSetupContext, ServiceDefinition, ServiceState } from "@cyrnel/sdk";

class MyAdapter implements AdapterModule {
  private state = new Map<string, ServiceState>();

  async setup(_context: ModuleSetupContext) {}
  async teardown() { this.state.clear(); }

  async generateDefinition(input: string): Promise<ServiceDefinition> {
    return {
      name: "...",
      description: "...",
      configSchema: { type: "object", properties: {} },
      secretsSchema: { type: "object", properties: {} },
      adapterDomain: { /* parsed metadata */ },
      tools: [
        {
          id: "ping",
          name: "ping",
          description: "Health check",
          inputSchema: { type: "object" },
          outputSchema: { type: "object" },
          adapterDomain: { /* per-tool routing info */ },
        },
      ],
    };
  }

  async hydrateService(state: ServiceState): Promise<void> {
    this.state.set(state.id, state);
  }

  async dehydrateService(id: string): Promise<void> {
    this.state.delete(id);
  }

  async invoke(input: InvokeInput): Promise<unknown> {
    const svc = this.state.get(input.serviceId);
    if (!svc) throw new Error(`unknown service ${input.serviceId}`);
    // ...use svc.adapterDomain / svc.config / svc.secrets to issue the call
    return { ok: true };
  }
}

const configSchema = { type: "object", properties: {} } as const;
const secretsSchema = { type: "null" } as const;

export default { configSchema, secretsSchema, instantiate: () => new MyAdapter() };
```

## Full Example

See the [HTTP adapter example](https://github.com/actelos/mci/tree/main/examples/adapter-module)
in the repository for a complete, working adapter that accepts a JSON service
definition describing REST endpoints and calls them over HTTP. It stores
per-service base URLs in `adapterDomain`, reads secrets for
`Authorization`, and routes each invocation to the correct endpoint.

See [`ServiceState`](/cyrnel/specs/types#servicestate-and-toolstate) for the shape
of the snapshot the host delivers to `hydrateService`, and
[`AdapterModule`](/cyrnel/specs/adapter-module) for the full interface contract.
