Iris Docs

Read Handlers

Workspace-discovered shell recipes that teach the read tool how to extract text from a file format.

A read handler is a directory containing a handler.json that maps a MIME type to a shell command. The read tool sniffs a file's real type from its magic bytes (never the filename) and, if a handler claims that MIME type, runs its command instead of dumping raw binary or falling through to the plain-text path. Handlers hot-reload without a restart — drop one in and the next read picks it up.

This is the same extension seam skills have, applied to file formats instead of agent behavior: no core PR needed to add a new format, and Iris can write her own the same way she writes skills.

Anatomy

read-handlers/
└── pdf-text/
    └── handler.json
{
	"name": "pdf-text",
	"mimeTypes": ["application/pdf"],
	"command": "pdftotext -layout {path} -",
	"timeoutSeconds": 30
}
  • mimeTypes — required, non-empty array. The MIME type(s) sniffed from a file's magic bytes that this handler claims.
  • command — required. A shell command template; {path} is substituted with the shell-escaped file path before it runs through the same sandboxed executor every other tool call uses.
  • timeoutSeconds — optional, defaults to 30.
  • overridesBuiltinImageHandling — optional, defaults to false. The read tool always sends jpg/png/gif/webp as image attachments through its built-in vision path. A handler claiming one of those MIME types is ignored unless this is set to true — e.g. to route images through OCR instead of vision. Without it, that MIME type is dropped from the handler at load time (with a warning), not silently honored.

A handler is deliberately not loadable code — no JS/TS module is ever imported into the running process. It's a shell command, run the same way bash tool calls already run, so a broken or malicious handler's blast radius is a bad shell command, not arbitrary code sharing the engine's own address space.

Load order and overrides

Handlers are discovered from <workspace>/read-handlers/ (symlinked to the repo's read-handlers/ directory for hot reload, same as skills). To override a core-shipped handler — e.g. swap pdftotext for an OCR-capable tool — ship a handler with the same directory name in your overlay; it replaces the core one in place, same override rule as skills. Two different-named handlers claiming the same MIME type is a load-time warning; the first one scanned wins, so rely on naming to override, not scan order.

What belongs in core

Core ships one default handler: pdf-text, extracting a PDF's text layer via pdftotext (poppler-utils, installed by bootstrap.sh). Scanned or image-only PDFs have no text layer and read back empty — there is no OCR fallback in core.

Additional formats (docx, pptx, xlsx, proprietary formats, OCR handlers) are overlay content — install-specific, like skills. Write one by hand, or ask Iris: the same self-extend protocol that scaffolds a skill applies here — identify the need, write handler.json in overlay/read-handlers/<name>/, commit before use, test with one safe file.

Edit this page on GitHub