Files
strukto-ai--mirage/AGENTS.md
T
Zecheng Zhang 924ec49796 Initial public release: Mirage v0.0.1-alpha.1
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.

Ships Python (mirage-ai) and TypeScript (@struktoai/mirage-*) SDKs,
a CLI, FUSE mounts, and adapters for OpenAI Agents SDK, Vercel AI
SDK, LangChain deepagents, Pydantic AI, CAMEL, OpenHands, Mastra,
Pi Coding Agent, plus FUSE-based integration with Claude Code and
Codex.

Apache 2.0 licensed.
2026-05-06 10:03:22 -07:00

4.3 KiB

AGENTS.md

MIRAGE is a package that allows you to mount anything as a filesystem and make it usable by AI Agents.

Repo Layout

This monorepo hosts two sibling implementations:

  • python/ — the Python package (mirage/, tests/, pyproject.toml, uv.lock).
  • typescript/ — the TypeScript monorepo (packages/core, packages/node, etc.).
  • docs/, examples/, .github/ — shared across both.

Run Python commands from python/, TypeScript commands from typescript/.

Development Setup

This project uses uv for Python dependency management. Install dependencies with:

cd python && uv sync --all-extras

Running examples

Examples under examples/python/ load .env.development from the repo root (cwd-relative). To keep cwd at the root while using the python/ venv, invoke the venv interpreter directly:

./python/.venv/bin/python examples/python/s3/s3.py

Avoid uv --directory python run ... for examples — it changes cwd to python/ and breaks load_dotenv(".env.development").

Backward Compatibility

  • No need to consider backward compatibility for the code.

Create a PR

When asked to create a PR, please follow the following steps:

  1. Run pre-commit run --all-files from the repo root to lint and format the code.
  2. Run cd python && uv run pytest to run the Python tests.
  3. Run git add -A to add all changes.
  4. Run git checkout -b <branch-name> to create a new branch.
  5. Run git commit -m "<commit-message>" to commit the changes.
  6. Run git push origin <branch-name> to push the changes to the remote repository.
  7. Run gh pr create --title "<pr-title>" --body "<pr-body>" to create a PR.

Commands

Linting and Formatting

After making major changes, run pre-commit from the repo root to ensure code quality:

./python/.venv/bin/pre-commit run --all-files

Invoke the venv's pre-commit binary directly (not via uv --directory python run) so cwd stays at the repo root — otherwise git ls-files only lists files under python/ and examples/ gets silently skipped.

Type Conventions

  • Paths must always be represented as PathSpec, never raw strings. All functions that accept or return paths use list[str | PathSpec] where str is for text arguments and PathSpec is for paths. Never pass a path as a plain str — wrap it in PathSpec.

Rules

  • Avoid add any comments or docstrings on the top of the file.
  • Do not create nested functions.
  • Add type to Args for docstring.
  • Do not add comment after each line of code in the format of "# 10MB - trigger segmentation for files larger than this". The most you can add is "# 10MB".
  • For all imports you need to put to the top of the file. Don't have imports within each function.
  • No circular imports. If putting an import at the top would cause a cycle, that's a sign the dependency direction is wrong — fix the design (dependency injection, splitting modules, moving the shared piece to a leaf), don't paper over it with function-local lazy imports. Verify by checking that running cd python && uv run python -c "import <every changed module>" succeeds without ImportError.
  • Never silently swallow exceptions. try: ... except: pass (or except SomeError: pass) hides real bugs. If you genuinely need to ignore an error, log it (logger.debug(...)) or document loudly why it's safe. Default behavior should be: let the exception propagate. Especially never silently swallow RuntimeError — it usually signals something deeper (event loop in wrong state, recursion limit, etc.) that you need to actually fix.
  • Never call asyncio.run() inside a sync function that might be invoked under an outer event loop. It will raise RuntimeError: asyncio.run() cannot be called from a running event loop. If you need async behavior from a sync API, either: (a) make the calling function async, (b) operate on the underlying sync state directly (e.g. write to a dict instead of calling an async setter), or (c) use a sync alternative of the same library (e.g. redis.Redis instead of redis.asyncio.Redis). Do NOT wrap with try/except RuntimeError: pass — that masks the bug AND leaks the unawaited coroutine.
  • Please don't change any file name unless I ask you to do so.
  • Don't add too many printings or comments in the code.
  • Don't add README.md unless I ask you to do so.
  • Use uv add to install new dependencies.