# Tool Adapters
Squid Mesh exposes a small tool boundary for workflow steps that need to talk
to external systems.
## Contract
Tool adapters implement `SquidMesh.Tools.Adapter` and are invoked through
`SquidMesh.Tools.invoke/4`.
```elixir
{:ok, result} =
SquidMesh.Tools.invoke(MyApp.Tools.SomeAdapter, request, context)
```
The shared contract is:
- request: a map owned by the adapter
- context: a workflow or step context map
- success: `{:ok, %SquidMesh.Tools.Result{}}`
- failure: `{:error, %SquidMesh.Tools.Error{}}`
## Normalized Result
`SquidMesh.Tools.Result` contains:
- `adapter`: the adapter module
- `payload`: the normalized adapter response
- `metadata`: adapter metadata such as request method or URL
## Normalized Error
`SquidMesh.Tools.Error` contains:
- `adapter`: the adapter module
- `kind`: normalized error kind
- `message`: stable human-readable message
- `details`: adapter-specific details in a plain map
- `retryable?`: whether the failure is a reasonable candidate for workflow retry
Steps can convert tool errors into plain maps with
`SquidMesh.Tools.Error.to_map/1` before returning them as workflow step
failures.
## HTTP Adapter
`SquidMesh.Tools.HTTP` is the first concrete adapter.
Supported request shape:
- `method`
- `url`
- `headers`
- `params`
- `body`
- `json`
- `timeout`
Successful responses are normalized to:
- `status`
- `headers`
- `trailers`
- `body`
HTTP responses with status `>= 400`, transport failures, and timeouts are
normalized into `SquidMesh.Tools.Error`.
## Retry Boundary
The HTTP adapter disables Req's built-in retry loop.
That keeps retry policy in one place:
- adapters report the first failure
- workflow steps declare retry policy
- Squid Mesh and Oban schedule the next step attempt
This keeps transport behavior predictable and avoids stacking HTTP-client
retries underneath workflow retries.