# unreadable.gg for agents

Agents can use the same API as any other program. There's also an MCP server, and every page has a markdown version.

## pages for agents

[llms.txt](https://unreadable.gg/llms.txt) lists these docs. [llms-full.txt](https://unreadable.gg/llms-full.txt) has every page in one file.

Every page is also markdown. Add `.md` to its address, like [`/docs/api.md`](https://unreadable.gg/docs/api.md), or send `Accept: text/markdown`.

If your agent can run commands, use curl, like in the [quickstart](https://unreadable.gg/docs#quickstart). The file goes straight from disk and never enters the model's context. Add `-o result.json` and only read the fields you need, like `verdict` and `notes`.

The full schema is at [`https://api.unreadable.gg/v1/openapi.json`](https://api.unreadable.gg/v1/openapi.json), with every option, note code and error code.

## mcp

`POST https://api.unreadable.gg/mcp`

The MCP server is stateless and only speaks revision `2026-07-28`. There's no `initialize` and no session. A client that starts with `initialize` (the older handshake) gets an "unsupported protocol version" error, so your client has to support the stateless revision.

Each request carries the protocol version and client capabilities in `_meta`. Its `MCP-Protocol-Version`, `Mcp-Method` and `Mcp-Name` headers must match the body.

It answers `server/discover`, `tools/list`, `tools/call` and `subscriptions/listen`.

Without a key, calls use your connection's free decompiles. To use a member's account, send `Authorization: Bearer ugk_...` with a key from the [account page](https://unreadable.gg/account), same as the [API](https://unreadable.gg/docs/api#accounts).

| tool | what it does |
| --- | --- |
| decompile | Decompiles one module from base64 `bytecode`. Returns a handle, the verdict, line and function counts, and notes by code. Includes the source if it's 120 lines or less. Takes the same [options](https://unreadable.gg/docs/api#options) as the API. Uses one free decompile. |
| decompile_many | Decompiles up to 16 named modules with one set of options. Returns a handle and summary for each, or its error. The same bytes under two names are decompiled once. Each unique module uses one free decompile. For more, or a whole `.rbxl`/`.rbxm`, use [the site](https://unreadable.gg) or the [stream](https://unreadable.gg/docs/stream). |
| list_functions | Every function in source order: id, name, first and last line, parent, and note count. |
| get_function | One function's source and notes, by id or name, with the functions it calls and is called by. |
| get_source | The whole source, or a range of lines. To change the code, patch and recompile the whole source. |
| search_source | The lines that contain a text or match a pattern, each with the function it's in. |
| list_notes | The [notes](https://unreadable.gg/docs/api#notes), or only the ones with one `code`. |
| compare | What changed between two handles: functions added, removed and changed, matched by name, with a diff of each changed one. Free. |
| explain_switch | What one [switch](https://unreadable.gg/docs/readability#switches) or preset does. No handle needed. Free. |

Each note says which function it's about. `get_function` only lists calls to local functions by name, since those are the ones the decompiler can prove. Calls through tables or globals aren't listed.

Pick the preset by what the source is for:

| preset | for |
| --- | --- |
| faithful | Auditing, patching and recompiling, or matching a crash's line numbers. |
| balanced | Understanding the code. |
| readable | Skimming. |

## handles

To keep the file out of the model's context, send it from disk to `/v1/handles`, then read the result with the tools:

```sh
curl https://api.unreadable.gg/v1/handles \
  -H "Content-Type: application/octet-stream" \
  --data-binary @module.luac
```

It takes the same request and key as `/v1/decompile`, and answers like the `decompile` tool.

A handle works for one hour. The result is encrypted with a key that only exists in the handle, so nobody can read it without the handle, us included ([privacy](https://unreadable.gg/privacy#agents)).

If a tool returns `handle-not-ready` in the first two minutes, call it again after `retryAfter` seconds.

To send up to 16 modules at once, use `multipart/form-data`. Make each module a file part, named by its filename. Add an optional `options` part with the options as JSON. The whole body is at most 8 MiB, and it answers like `decompile_many`:

```sh
curl https://api.unreadable.gg/v1/handles \
  -F file=@a.luac -F file=@b.luac \
  -F 'options={"preset":"balanced"}'
```

Each file is held to your [file size limit](https://unreadable.gg/docs/api#limits): 2 MiB free, 8 MiB for members.
