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. For the full
interface reference see AdapterModule.
Minimal Skeleton
Logging
The host owns all logging - your module never creates a logger. The logger it
receives in setup already carries your module’s identity (moduleId,
moduleType, adapterId), and every entry is tagged type: "module".
- Call
context.logger.redact(patterns) to opt into self-managed
reduction. Declare redactionPatterns in your own configSchema and read
it back from context.config: the host never supplies patterns for you.
Your patterns merge additively on top of a non-disableable baseline
(secrets / tokens / passwords / authorization).
- Use
logger.child({ ... }) to scope a logger for a phase or a specific
invocation. child accepts only phase/event; the host-owned correlation
fields (serviceId, toolId, executionId, …) are merged in by the host
and cannot be forged.
- Emit structured logs with
logger.info({ event, ...payload }, "message").
All six levels are available: trace, debug, info, warn, error,
fatal.
Full Example
See the HTTP adapter example
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 for the shape
of the snapshot the host delivers to hydrateService, and
AdapterModule for the full interface contract. Last modified on August 25, 2026