Files
Zecheng Zhang 43e8a67180 Merge pull request #877 from strukto-ai/fix/os-verb-routing
fix(os): route every path-taking os verb through the workspace
2026-08-21 04:04:52 -07:00

521 lines
15 KiB
TOML

[project]
name = "mirage-ai"
version = "0.0.5"
description = "A unified virtual filesystem for AI agents. Mount S3, Google Drive, Slack, Gmail, GitHub, Linear, Notion, Postgres, MongoDB, SSH, and more behind one filesystem so agents read, write, and pipe across services with familiar shell commands."
readme = "README.md"
license = "Apache-2.0"
license-files = ["LICENSE"]
requires-python = ">=3.11"
authors = [
{ name = "Zecheng Zhang", email = "zecheng@strukto.ai" },
]
keywords = [
"ai-agents",
"filesystem",
"vfs",
"fuse",
"s3",
"google-drive",
"slack",
"agent-tools",
"shell",
"rag",
]
classifiers = [
"Development Status :: 3 - Alpha",
"Intended Audience :: Developers",
"Operating System :: POSIX :: Linux",
"Operating System :: MacOS :: MacOS X",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"Topic :: Software Development :: Libraries :: Python Modules",
"Topic :: System :: Filesystems",
"Topic :: Scientific/Engineering :: Artificial Intelligence",
]
dependencies = [
"aiofiles>=24.1.0",
"aiohttp>=3.14.2",
"fastapi>=0.135.1",
"httpx>=0.28.1",
"python-multipart>=0.0.27",
"orjson>=3.11",
"pyyaml>=6.0.3",
"tree-sitter>=0.25.2",
"tree-sitter-bash>=0.25.1",
"typer>=0.12.0",
"uvicorn[standard]>=0.41.0",
"jq>=1.11.0",
"pyjwt[crypto]>=2.13.0",
"dulwich>=1.2.5",
"tenacity>=9.1.4",
"mcp>=1.28.1",
]
[project.urls]
Homepage = "https://www.strukto.ai/"
Repository = "https://github.com/strukto-ai/mirage"
Documentation = "https://docs.mirage.strukto.ai"
Issues = "https://github.com/strukto-ai/mirage/issues"
[project.scripts]
mirage = "mirage.cli.main:main"
[build-system]
requires = ["setuptools>=68"]
build-backend = "setuptools.build_meta"
[tool.setuptools.packages.find]
include = ["mirage*"]
[tool.setuptools.package-data]
# py.typed is PEP 561 consent: without the marker a type checker refuses
# to read an installed package's annotations and every mirage import
# resolves to Any, so our own gated-at-zero mypy proves nothing to anyone
# downstream. It caught the 0.0.5 build_resource break in one line.
mirage = ["**/*.lua", "py.typed"]
[project.optional-dependencies]
# --- python runtime (sandboxed python3 default) ---
# Pinned exactly: monty's API is still moving fast (0.0.19 replaced the whole
# execution model), and upstream pins its own worker binary the same way.
monty = ["pydantic-monty==0.0.19"]
wasi = ["wasmtime>=46"]
quickjs = ["wasmtime>=46"]
# --- storage / object stores ---
s3 = ["aioboto3>=13.0"]
r2 = ["aioboto3>=13.0"]
gcs = ["aioboto3>=13.0"]
oci = ["aioboto3>=13.0"]
databricks = ["databricks-sdk>=0.72.0"]
# --- network / remote ---
ssh = ["asyncssh>=2.23.0"]
nextcloud = ["opendal>=0.47.1"]
# --- huggingface ---
hf = ["opendal>=0.47.1"]
# --- mount ---
fuse = ["mfusepy>=1.0.0"]
# --- mongodb ---
mongodb = ["pymongo>=4.9"]
# --- gridfs ---
gridfs = ["pymongo>=4.9"]
# --- postgres ---
postgres = ["asyncpg>=0.30.0"]
# --- redis ---
redis = ["redis[hiredis]>=5.0"]
# --- mail ---
email = ["aioimaplib>=2.0.1", "aiosmtplib>=5.1.0"]
# --- data ---
# --- observability ---
langfuse = ["langfuse>=4.2.0"]
# --- chroma ---
# thin HTTP-only client; the accessor uses AsyncHttpClient exclusively
chroma = ["chromadb-client>=1.0.0"]
# --- qdrant ---
qdrant = ["qdrant-client[fastembed]>=1.18.0"]
# --- anthropic ---
anthropic = ["anthropic>=0.88"]
# --- openai ---
openai = ["openai>=2.46.0", "openai-agents>=0.18.3"]
# --- pydantic-ai ---
pydantic-ai = [
"pydantic-ai-slim[anthropic,openai]>=2.13.0",
"pydantic-ai-backend>=0.2.16",
]
# --- deepagents ---
deepagents = [
"deepagents>=0.7.6",
]
# --- openhands ---
openhands = [
"openhands-sdk>=1.36.1 ; python_full_version >= '3.12'",
"openhands-tools>=1.36.1 ; python_full_version >= '3.12'",
]
# --- agno ---
agno = [
"agno>=2.7.4",
]
# --- claude-agent-sdk ---
claude-agent-sdk = [
"claude-agent-sdk>=0.2.123",
]
# --- camel ---
camel = [
"camel-ai>=0.2.90,<0.3",
"markitdown>=0.1.5",
]
# --- sandboxes ---
daytona = [
"daytona>=0.176.0",
]
# --- meta: install everything ---
all = [
"mirage-ai[s3]",
"mirage-ai[r2]",
"mirage-ai[gcs]",
"mirage-ai[oci]",
"mirage-ai[databricks]",
"mirage-ai[ssh]",
"mirage-ai[nextcloud]",
"mirage-ai[hf]",
"mirage-ai[fuse]",
"mirage-ai[mongodb]",
"mirage-ai[gridfs]",
"mirage-ai[postgres]",
"mirage-ai[redis]",
"mirage-ai[email]",
"mirage-ai[langfuse]",
"mirage-ai[mem0]",
"mirage-ai[chroma]",
"mirage-ai[qdrant]",
"mirage-ai[anthropic]",
"mirage-ai[openai]",
"mirage-ai[pydantic-ai]",
"mirage-ai[deepagents]",
"mirage-ai[openhands]",
"mirage-ai[agno]",
"mirage-ai[claude-agent-sdk]",
"mirage-ai[daytona]",
"mirage-ai[e2b]",
]
sandbox = [
"mirage-ai[s3]",
"mirage-ai[r2]",
"mirage-ai[gcs]",
"mirage-ai[oci]",
"mirage-ai[databricks]",
"mirage-ai[ssh]",
"mirage-ai[nextcloud]",
"mirage-ai[hf]",
"mirage-ai[fuse]",
"mirage-ai[mongodb]",
"mirage-ai[gridfs]",
"mirage-ai[postgres]",
"mirage-ai[redis]",
"mirage-ai[email]",
"mirage-ai[langfuse]",
"mirage-ai[chroma]",
"mirage-ai[qdrant]",
]
lancedb = [
"lancedb>=0.33.0",
]
mem0 = [
"mem0ai>=2.0.6",
]
e2b = [
"e2b>=2.0.0",
]
[tool.uv]
conflicts = [
[
{ extra = "camel" },
{ extra = "openai" },
],
[
{ extra = "camel" },
{ extra = "openhands" },
],
[
{ extra = "camel" },
{ extra = "pydantic-ai" },
],
[
{ extra = "camel" },
{ extra = "all" },
],
]
[dependency-groups]
dev = [
"aioresponses>=0.7.6",
"python-dotenv>=1.2.2",
"grpcio>=1.78.0",
"grpcio-tools>=1.78.0",
"moto[s3,server]>=5.1.22",
"pre-commit",
"pytest",
"pytest-asyncio>=0.24.0",
"pytest-cov>=7.0.0",
"pytest-httpx>=0.36.0",
"mypy>=2.3.0",
"lz4>=4.4.5",
]
[tool.flake8]
exclude = ["mirage/commands/remote/grpc/proto/command_pb2.py", "mirage/commands/remote/grpc/proto/command_pb2_grpc.py"]
per-file-ignores = [
"python/mirage/resource/*/prompt.py:E501",
]
[tool.pytest.ini_options]
testpaths = ["tests"]
addopts = "--cov=mirage --cov-report=term-missing -q --import-mode=importlib"
markers = [
"network: tests that require network access",
"no_host_override: skip the tests/server/conftest autouse MIRAGE_ALLOWED_HOSTS=* override",
"no_auth_override: skip the tests/server/conftest autouse MIRAGE_AUTH_MODE=local-with-no-token override",
]
[tool.mypy]
python_version = "3.12"
packages = ["mirage"]
ignore_missing_imports = true
warn_unused_ignores = true
warn_redundant_casts = true
check_untyped_defs = true
no_implicit_optional = true
disallow_any_generics = true
# Every module, rather than an allowlist of 54 against 1826. The
# allowlist could only ever name what someone remembered to add, so the
# handles CLAUDE.md prescribes types for (`accessor: Accessor`,
# `index: IndexCacheStore | None`) went unannotated everywhere it did
# not reach. TypeScript gets the same guarantee from `strict` in
# tsconfig.base.json, inherited by every package.
disallow_untyped_defs = true
warn_return_any = true
# The inversion's remainder, and it only shrinks. Before this, an
# allowlist of 54 modules opted *in* to annotation checking, so the
# default for 1826 modules was unchecked and every new file joined the
# unchecked side. The default is now strict and this list is what has
# not been annotated yet -- delete entries as directories are cleared,
# never add one. A new module is checked the day it lands.
[[tool.mypy.overrides]]
module = [
"mirage.accessor._hf",
"mirage.accessor.gdocs",
"mirage.accessor.gdrive",
"mirage.accessor.gmail",
"mirage.accessor.gsheets",
"mirage.accessor.gslides",
"mirage.accessor.history",
"mirage.accessor.nextcloud",
"mirage.agents.agno.toolkit",
"mirage.agents.camel.file",
"mirage.agents.openai_agents.runner",
"mirage.agents.openai_agents.shell",
"mirage.agents.openhands.workspace",
"mirage.bridge.thread",
"mirage.cache",
"mirage.cache.file.ram",
"mirage.cache.file.redis",
"mirage.cache.lock",
"mirage.cli.client",
"mirage.cli.output",
"mirage.cli.workspace",
"mirage.commands.builtin.dify.cat",
"mirage.commands.builtin.generic.crossmount.detect",
"mirage.commands.builtin.generic.rm_cmd",
"mirage.commands.builtin.generic_bind.archive_io",
"mirage.commands.builtin.generic_bind.builders.du",
"mirage.commands.builtin.generic_bind.builders.sed",
"mirage.commands.builtin.generic_bind.factory",
"mirage.commands.builtin.generic_bind.provision",
"mirage.commands.builtin.github.du",
"mirage.commands.builtin.github.grep",
"mirage.commands.builtin.gmail.grep",
"mirage.commands.builtin.grep_helper",
"mirage.commands.builtin.utils.limit",
"mirage.commands.cli.builtin.git.format",
"mirage.commands.cli.builtin.git.objects",
"mirage.commands.cli.builtin.linear.util",
"mirage.commands.config",
"mirage.config",
"mirage.core.box.resolve",
"mirage.core.chroma.stat",
"mirage.core.databricks_volume.copy",
"mirage.core.databricks_volume.read",
"mirage.core.databricks_volume.stat",
"mirage.core.databricks_volume.stream",
"mirage.core.discord.members",
"mirage.core.discord.read",
"mirage.core.discord.readdir",
"mirage.core.disk.exists",
"mirage.core.disk.read",
"mirage.core.email.client",
"mirage.core.email._parse",
"mirage.core.github.readdir",
"mirage.core.github.repo",
"mirage.core.gmail.labels",
"mirage.core.gmail.messages",
"mirage.core.hf_buckets.read",
"mirage.core.hf_buckets.readdir",
"mirage.core.jq.stream",
"mirage.core.lancedb.query",
"mirage.core.lancedb.read",
"mirage.core.lancedb.readdir",
"mirage.core.langfuse.client",
"mirage.core.mem0.client",
"mirage.core.mongodb.client",
"mirage.core.mongodb._sampler",
"mirage.core.mongodb.search",
"mirage.core.mongodb.stream",
"mirage.core.nextcloud.read",
"mirage.core.nextcloud.readdir",
"mirage.core.nextcloud.search.query",
"mirage.core.notion.read",
"mirage.core.postgres.client",
"mirage.core.postgres.search",
"mirage.core.qdrant.read",
"mirage.core.qdrant.readdir",
"mirage.core.s3.read",
"mirage.core.slack.readdir",
"mirage.core.slack.users",
"mirage.core.ssh.rm",
"mirage.core.ssh.stream",
"mirage.core.trello.stat",
"mirage.fuse.core",
"mirage.fuse.darwin",
"mirage.fuse.fs",
"mirage.fuse.mount",
"mirage.observe.context",
"mirage.ops.chroma.grep",
"mirage.ops.chroma.search",
"mirage.ops.dify.grep",
"mirage.ops.dify.search",
"mirage.ops.gcal.read",
"mirage.ops.gdocs.read",
"mirage.ops.generic.factory",
"mirage.ops.gsheets.read",
"mirage.ops.gslides.read",
"mirage.ops.ops",
"mirage.ops.registry",
"mirage.resource",
"mirage.resource.box.box",
"mirage.resource.chroma",
"mirage.resource.chroma.chroma",
"mirage.resource.databricks_volume",
"mirage.resource.databricks_volume.databricks_volume",
"mirage.resource.dev.dev",
"mirage.resource.dify",
"mirage.resource.dify.dify",
"mirage.resource.discord",
"mirage.resource.discord.discord",
"mirage.resource.disk.disk",
"mirage.resource.dropbox",
"mirage.resource.dropbox.dropbox",
"mirage.resource.email",
"mirage.resource.email.email",
"mirage.resource.gcal",
"mirage.resource.gcal.gcal",
"mirage.resource.gdocs",
"mirage.resource.gdocs.gdocs",
"mirage.resource.gdrive",
"mirage.resource.gdrive.gdrive",
"mirage.resource.github.github",
"mirage.resource.gmail",
"mirage.resource.gmail.gmail",
"mirage.resource.gridfs.gridfs",
"mirage.resource.gsheets",
"mirage.resource.gsheets.gsheets",
"mirage.resource.gslides",
"mirage.resource.gslides.gslides",
"mirage.resource.hf_buckets.hf_buckets",
"mirage.resource.hf_datasets.hf_datasets",
"mirage.resource.hf_models.hf_models",
"mirage.resource.hf_spaces.hf_spaces",
"mirage.resource.history.history",
"mirage.resource.jaeger",
"mirage.resource.jaeger.jaeger",
"mirage.resource.lancedb",
"mirage.resource.lancedb.lancedb",
"mirage.resource.langfuse",
"mirage.resource.langfuse.langfuse",
"mirage.resource.linear",
"mirage.resource.linear.linear",
"mirage.resource.loader",
"mirage.resource.mem0",
"mirage.resource.mongodb",
"mirage.resource.mongodb.mongodb",
"mirage.resource.nextcloud.nextcloud",
"mirage.resource.notion",
"mirage.resource.notion.notion",
"mirage.resource.onedrive.onedrive",
"mirage.resource.postgres",
"mirage.resource.postgres.postgres",
"mirage.resource.qdrant",
"mirage.resource.qdrant.qdrant",
"mirage.resource.ram",
"mirage.resource.ram.ram",
"mirage.resource.redis",
"mirage.resource.redis.redis",
"mirage.resource.registry",
"mirage.resource.s3.s3",
"mirage.resource.sharepoint.sharepoint",
"mirage.resource.slack",
"mirage.resource.slack.slack",
"mirage.resource.ssh.ssh",
"mirage.resource.trello",
"mirage.resource.trello.trello",
"mirage.runtime.python.monty.osaccess",
"mirage.runtime.vfs",
"mirage.runtime.wasm.host",
"mirage.server.app",
"mirage.server.routers.execute",
"mirage.server.routers.jobs",
"mirage.server.routers.sessions",
"mirage.server.summary",
"mirage.server.version.api",
"mirage.server.version.restore",
"mirage.server.version.state_diff",
"mirage.server.version.state_tree",
"mirage.shell.arith",
"mirage.shell.parse",
"mirage.workspace.dispatcher.dispatcher",
"mirage.workspace.executor.builtins.scope",
"mirage.workspace.executor.control",
"mirage.workspace.executor.jobs",
"mirage.workspace.executor.pipes",
"mirage.workspace.executor.redirect",
"mirage.workspace.expand.node",
"mirage.workspace.expand.variable",
"mirage.workspace.mount.mount",
"mirage.workspace.mount.namespace",
"mirage.workspace.mount.storage",
"mirage.workspace.node.command_dispatch",
"mirage.workspace.node.execute_node",
"mirage.workspace.node.program",
"mirage.workspace.node.provision_node",
"mirage.workspace.node.test_expr",
"mirage.workspace.provision.command",
"mirage.workspace.provision.control",
"mirage.workspace.provision.pipes",
"mirage.workspace.provision.redirect",
"mirage.workspace.session",
"mirage.workspace.snapshot.api",
"mirage.workspace.snapshot.manifest",
"mirage.workspace.snapshot.state",
"mirage.workspace.snapshot.tar_io",
"mirage.workspace.workspace.cache",
"mirage.workspace.workspace.execute",
"mirage.workspace.workspace.workspace",
]
disallow_untyped_defs = false
warn_return_any = false