Documentation Index
Fetch the complete documentation index at: https://docs.mirage.strukto.ai/llms.txt
Use this file to discover all available pages before exploring further.
Unified Hands
Mirage gives agents one unified way to act across systems. Instead of learning a different action surface for every backend, agents can work through mounted paths, familiar Unix commands, and a lightweight stream-based execution model. These commands are Mirage’s hands. They stay simple on purpose: read, write, search, transform, and compose across systems through one interface.Why The Hands Stay Lightweight
Mirage is not trying to expose every backend as a giant in-process client library. It is trying to give agents a practical way to do work. That is why the design stays lightweight:- commands operate on paths and byte streams
- remote and local systems use the same shell-shaped interface
- composition happens through pipes, files, and command output
- cleanup and lifecycle stay explicit
Why Async Fits The Hands
Mirage has to work well across local files, remote APIs, object storage, streamed command output, and cleanup steps that may continue after a command returns. A synchronous, fully buffered model would either block too much or hide too much. Mirage instead treats command execution and I/O as naturally asynchronous, so the same hands can work consistently across systems. This keeps the action surface simple while still supporting long reads, pipelines, and non-blocking cleanup.Hands Work In Bytes, Not Objects
The hands move bytes, not objects. That choice is deliberate, and it is what lets the same small set of commands act across every backend. Consider the alternative. If every tool returned a backend-specific object shape, likeS3Object, SlackMessage, or LinearIssue, then every new command has to learn every backend’s type, and every new backend has to be taught to every command. (This is the M × N integration problem the Architecture page covers in full.)
Bytes collapse it. Every command reads bytes and writes bytes. Every backend produces and consumes bytes. grep does not need to know whether its input came from local disk, an S3 object, or a generated stream. It just reads bytes. Add a new command and it works with every existing source. Add a new source and every existing command can already act on it.
Two other reasons this fits the hands:
- In-distribution for LLMs. Models have seen an enormous amount of shell and text-stream interaction in training. Byte-shaped hands feel native; bespoke object schemas are a sparser, newer signal.
- Composable through pipes. Bytes chain. A CSV in object storage, a Markdown file on GitHub, and the output of a transform command can all flow through the same pipeline. Custom response types cannot.
- commands consume and produce byte streams
- resources expose files and paths instead of custom response types
- higher-level structure stays optional at the edge
Why This Fits Python and TypeScript
Both Python and TypeScript are increasingly used inside async frameworks, async servers, and agent applications that already expect non-blocking I/O. Mirage aligns with that direction instead of fighting it.- Python.
await-driven command execution and cleanup, compatible with the async stacks that dominate modern Python: FastAPI, Starlette, and the asyncio runtime they build on. - TypeScript. The same model maps cleanly onto promises, Node.js streams, and modern frameworks like Hono or Express that expect event-loop-based I/O.
What This Buys Agents
- One interface for acting across local and remote systems.
- Better composability across resources.
- Streaming behavior that works for pipelines and large reads.
- Explicit lifecycle control for execution, caching, and cleanup.
- Finer-grained control over how agents read and write, which is better for security than scattered implicit backend mutations.