# Writing an adapter

> Teach VOID the inverses for a tool it does not know yet.

Reading time: 11 min. Source: https://www.voidagent.tech/docs/adapters

An adapter maps tool calls to classes, snapshots and inverses. Shipping one is the difference between a tool being R3 by default and being properly reversible.

> v1.0.1. TUI and MCP shipped. Desktop app in beta for macOS, Windows and iOS, by application. The import at the top of this sample names a package inside the product repository, at version 0.1.0, that is private and unpublished. It resolves from a clone of that repository and cannot be installed from a registry, so the sample shows a shape rather than a line you can paste.

## Minimal adapter

```adapters/acme.ts
import { adapter, R } from "@void/sdk";

export default adapter({
  id: "acme",
  tools: {
    "acme.record.update": {
      effect: "write",
      class: R.R0,
      blastRadius: (args) => ({ systems: ["acme"], records: 1 }),
      snapshot: async (args, ctx) => ctx.client.get(args.id),
      inverse: (before) => ({ tool: "acme.record.update", args: before }),
    },
    "acme.record.delete": {
      effect: "write",
      class: R.R1,
      snapshot: async (args, ctx) => ctx.client.get(args.id),
      inverse: (before) => ({ tool: "acme.record.create", args: before }),
    },
    "acme.payout.send": {
      effect: "write",
      class: R.R3,
      inverse: null,
      reason: "settles to an external bank",
    },
  },
});
```

## Rules of thumb

- If you cannot write the inverse, the class is R2 or R3. Do not guess.
- A snapshot that cannot be verified by digest is not a snapshot.
- Blast radius should sample for bulk operations rather than enumerate.
- Prefer the narrowest API scope that still supports the inverse.

## Testing

```shell
$ void adapter test ./adapters/acme.ts
  + 3 tools declared
  + 2 inverses execute against the sandbox
  + 2 snapshots verify by digest
  ! acme.payout.send has no inverse, class R3 (expected)
```

> An adapter runs inside the process that loaded it, and it never phones home. Which process that is depends on which surface loaded it.

---

This document is the markdown form of https://www.voidagent.tech/docs/adapters, published for agents that read
text rather than a rendered page. It is generated from the same data the page
renders, so the two cannot disagree.

