Integration: Mirage
Give a Haystack Agent a bash shell over Mirage's unified virtual filesystem, mounting S3, Google Drive, Postgres and 50+ other backends as one filesystem
Table of Contents
Overview
Mirage is a unified virtual filesystem for AI agents: it
mounts heterogeneous backends โ object storage (S3, GCS, R2), databases (Postgres, MongoDB, Redis),
and SaaS apps (Google Drive, Gmail, Slack, GitHub, Notion) โ as a single filesystem, so every service
speaks the same familiar Unix semantics. An agent can ls, cat, grep and pipe across mounts
exactly as it would on local disk, without learning a new API for each backend.
The mirage-haystack integration wraps Mirage as a Haystack
Tool that an
Agent can invoke to run bash commands across the
mounted filesystem. Instead of pre-loading data into a pipeline, you hand the agent one well-described
tool and let it explore the mounts itself to answer a question.
Installation
pip install mirage-haystack
Usage
Components
This integration introduces the following:
MirageMount: A declarative, serializable description of a single backend mounted into the workspace โ its mountpath(e.g./s3), its Mirageresourcename (e.g."s3","gdrive","postgres"), itsconfig, and whether it isread_only. Credentials can be passed as HaystackSecrets. CallMirageMount.available_resources()to list every backend name you can mount.MirageWorkspace: Holds a list ofMirageMounts and lazily builds the livemirage.Workspaceon first use. It serializes cleanly (resolvingSecrets only at build time) and can also be run directly viarun()/run_async().MirageShellTool: A HaystackToolthat exposes the workspace’sexecutesurface to anAgentthrough a singlecommandparameter. Output is normalized to text and truncated before it reaches the model. It carries the security guards (allowed_commands,denied_paths) described below.
Use with a Haystack Agent
Mount a directory (or any Mirage backend) read-only and give an Agent a MirageShellTool it can
drive with ordinary bash โ the agent explores the files itself to answer:
from haystack.components.agents import Agent
from haystack.components.generators.chat import OpenAIChatGenerator
from haystack.dataclasses import ChatMessage
from haystack_integrations.tools.mirage import MirageMount, MirageShellTool, MirageWorkspace
workspace = MirageWorkspace(
mounts=[
MirageMount(path="/data", resource="ram"),
MirageMount(path="/s3", resource="s3", config={"bucket": "my-bucket"}, read_only=True),
]
)
tool = MirageShellTool(workspace, allowed_commands=["ls", "cat", "grep", "head", "wc", "cp"])
agent = Agent(
chat_generator=OpenAIChatGenerator(model="gpt-4o-mini"),
tools=[tool],
system_prompt=(
"A virtual filesystem is available through the `mirage_shell` tool. Use bash commands "
"(ls, cat, grep, wc, ...) to inspect the mounts before answering. Base your answer only "
"on what the files actually show."
),
)
agent.warm_up()
result = agent.run(
messages=[ChatMessage.from_user("How many lines in /s3/log.txt mention 'alert'?")]
)
print(result["messages"][-1].text)
tool.close()
Every backend is mounted the same way โ swap the MirageMount for the one you need. Values that are
credentials should be wrapped in a Secret:
from haystack.utils import Secret
from haystack_integrations.tools.mirage import MirageMount
MirageMount(path="/data", resource="ram") # in-memory scratch
MirageMount(path="/local", resource="disk", config={"root": "/srv/data"}) # local disk
MirageMount(path="/s3", resource="s3", config={"bucket": "my-bucket"}, read_only=True)
MirageMount(
path="/drive",
resource="gdrive",
config={"client_id": "...", "refresh_token": Secret.from_env_var("GDRIVE_REFRESH_TOKEN")},
read_only=True,
)
Run the workspace directly
You don’t need an Agent to use a workspace โ call run() to execute a command yourself. This is
handy for testing mounts or composing across backends in plain Python:
from haystack_integrations.tools.mirage import MirageMount, MirageWorkspace
ws = MirageWorkspace(
mounts=[
MirageMount(path="/data", resource="ram"),
MirageMount(path="/s3", resource="s3", config={"bucket": "my-bucket"}, read_only=True),
]
)
print(ws.run("grep -r alert /s3/logs | wc -l"))
ws.close()
Security model
Mirage never shells out to the host: every command runs inside Mirage’s own virtual-filesystem interpreter. Three controls shape what an Agent can do:
- Per-mount read-only mode (
MirageMount(..., read_only=True)) is the authoritative write boundary. Mirage refuses any write to a read-only mount regardless of the command used, so this is how you prevent modification or deletion. Mount anything the Agent should not change as read-only. - The command allowlist (
allowed_commands) restricts which commands may run. It is enforced against every command Mirage would execute, including commands nested inside$(...), backticks,<(...)and subshells, sols "$(rm x)"is rejected unlessrmis also allowed. Treat it as a best-effort filter to steer the Agent, not a sandbox: allowing a command that itself runs other commands (eval,bash,sh,source,xargs,timeout) effectively allows anything, so do not list those for untrusted/hosted use. denied_pathsrejects any command whose text references one of the given path substrings.
License
mirage-haystack is distributed under the terms of the
Apache-2.0 license.
